Compare commits
1175 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e987ac99e | ||
|
|
99a073484b | ||
|
|
831a860ce2 | ||
|
|
610a7feeca | ||
|
|
6275b14570 | ||
|
|
b2bf89996f | ||
|
|
7b8be18bd6 | ||
|
|
14b55e118c | ||
|
|
fe59f8bca7 | ||
|
|
ede900560d | ||
|
|
376a5b89c2 | ||
|
|
cd3b091649 | ||
|
|
1df7d0b2c3 | ||
|
|
485e2ff3d7 | ||
|
|
898aca526d | ||
|
|
129a386f42 | ||
|
|
bbb9f2d906 | ||
|
|
1bc8826aac | ||
|
|
586490c31a | ||
|
|
a2a142e546 | ||
|
|
e138e49e27 | ||
|
|
9212f14ffd | ||
|
|
27379c8f3f | ||
|
|
331dd51255 | ||
|
|
29bb629928 | ||
|
|
a5652f24f3 | ||
|
|
299db632be | ||
|
|
dc8e726b26 | ||
|
|
4398b0dde6 | ||
|
|
404379287f | ||
|
|
1a5a0a798a | ||
|
|
2793c61436 | ||
|
|
bfd18f1e3c | ||
|
|
271889cb78 | ||
|
|
62722e26b9 | ||
|
|
ff8e97bb97 | ||
|
|
4a2213c856 | ||
|
|
4eb0810099 | ||
|
|
63fe824223 | ||
|
|
7ee376827b | ||
|
|
9ffc6dd32d | ||
|
|
80230993c6 | ||
|
|
7b4f62ad1c | ||
|
|
3555582349 | ||
|
|
1e220ea385 | ||
|
|
a5d516f340 | ||
|
|
690763db2c | ||
|
|
a7c6200601 | ||
|
|
396ab56265 | ||
|
|
4f0b158c7d | ||
|
|
c7fa7bce3d | ||
|
|
10736d0638 | ||
|
|
7a13c37ead | ||
|
|
782c970228 | ||
|
|
6eb1da80c8 | ||
|
|
c612b569e0 | ||
|
|
9dafa1729d | ||
|
|
e245405325 | ||
|
|
1e0194d4bb | ||
|
|
7881a34fec | ||
|
|
1e206d4af6 | ||
|
|
049a5ffc9f | ||
|
|
51390bf6ca | ||
|
|
c9f905b396 | ||
|
|
58f36787f5 | ||
|
|
e750422cee | ||
|
|
66516f7a47 | ||
|
|
8152b8daea | ||
|
|
6245d4fb61 | ||
|
|
fce2753666 | ||
|
|
d9ee8386a3 | ||
|
|
c41e99f7e0 | ||
|
|
74b18e1d4f | ||
|
|
3e064cf976 | ||
|
|
d082a3a70b | ||
|
|
0f6f54635e | ||
|
|
a84ad79665 | ||
|
|
a3ea6de99d | ||
|
|
4c37716fb1 | ||
|
|
a68affad2a | ||
|
|
4a0d0ee3df | ||
|
|
b30d35b72b | ||
|
|
7190d106ab | ||
|
|
174aacd231 | ||
|
|
f51c075891 | ||
|
|
4ed660ffe8 | ||
|
|
c3609b59b2 | ||
|
|
14fa03b586 | ||
|
|
8818dc957c | ||
|
|
123c0971da | ||
|
|
fec30ce3e7 | ||
|
|
0349b56a6f | ||
|
|
4266a5b0b9 | ||
|
|
c25bdc27f7 | ||
|
|
75ad109b81 | ||
|
|
035497d3ec | ||
|
|
23473d2648 | ||
|
|
80f26a9459 | ||
|
|
57da276469 | ||
|
|
b05b144bd9 | ||
|
|
eee17ff269 | ||
|
|
f8ee2f5508 | ||
|
|
001cf56863 | ||
|
|
4ae09764cb | ||
|
|
4759a2d6b5 | ||
|
|
7e2ac57300 | ||
|
|
c845eabe69 | ||
|
|
7efcd3a614 | ||
|
|
947a2a7ce4 | ||
|
|
26c613faad | ||
|
|
4df39d1d2b | ||
|
|
0a51e4bf7c | ||
|
|
50fceedd10 | ||
|
|
fde4807f95 | ||
|
|
30ef1b3588 | ||
|
|
b7a86c9003 | ||
|
|
b47fba8d37 | ||
|
|
4a655509ed | ||
|
|
7d3537dbc0 | ||
|
|
c21e5ab383 | ||
|
|
4430003475 | ||
|
|
0e59a39006 | ||
|
|
e92ee33ee0 | ||
|
|
c25f161f99 | ||
|
|
886785acc2 | ||
|
|
11d389a871 | ||
|
|
af603074d5 | ||
|
|
ef78df0887 | ||
|
|
88dc9adaad | ||
|
|
5e92c69f64 | ||
|
|
04c761ba5f | ||
|
|
f324fe4ce4 | ||
|
|
5e15d68b9f | ||
|
|
9f61711154 | ||
|
|
6e8b14ab3b | ||
|
|
2d3f85dbea | ||
|
|
cf59208d7a | ||
|
|
fecfd2ffe4 | ||
|
|
2bf71c9fec | ||
|
|
0fcdc4b32c | ||
|
|
3671e373ce | ||
|
|
5fd9ff5093 | ||
|
|
32e4c45ef1 | ||
|
|
847bd705bb | ||
|
|
a7df6a480a | ||
|
|
5aa919b200 | ||
|
|
c79c8c77ca | ||
|
|
f9c4f9fa50 | ||
|
|
c1b2f097c2 | ||
|
|
08e71bd933 | ||
|
|
2ca1dc93c2 | ||
|
|
46e8de37f8 | ||
|
|
7c92f47be5 | ||
|
|
24262f3812 | ||
|
|
7fbd055c47 | ||
|
|
25dce9601d | ||
|
|
46e420a892 | ||
|
|
12d6688b6f | ||
|
|
12c1f633cc | ||
|
|
b94de1d201 | ||
|
|
59cc2d4ffd | ||
|
|
1facd77f78 | ||
|
|
902a245674 | ||
|
|
2fd881f172 | ||
|
|
fb3027b34d | ||
|
|
0145f18912 | ||
|
|
c4068f4dfc | ||
|
|
b002522cf0 | ||
|
|
d55fe9f988 | ||
|
|
a0a859cf77 | ||
|
|
7e251151c6 | ||
|
|
802366f44c | ||
|
|
647ed0a861 | ||
|
|
7c968cb91c | ||
|
|
1677bbbee3 | ||
|
|
fd69d4dda0 | ||
|
|
26f5087072 | ||
|
|
97a48e5267 | ||
|
|
38b2a5363b | ||
|
|
9aafc7da9a | ||
|
|
c0388be7c5 | ||
|
|
7284949cd7 | ||
|
|
d083ca165e | ||
|
|
b020d4bf11 | ||
|
|
ce62b2d01a | ||
|
|
ddfdd6c5c2 | ||
|
|
dc0f14021d | ||
|
|
faf6d4ff91 | ||
|
|
688c17613c | ||
|
|
19229449d4 | ||
|
|
467d9b1456 | ||
|
|
3f34e06eae | ||
|
|
ae1ee4d1cb | ||
|
|
572a14d171 | ||
|
|
cf3d09b39a | ||
|
|
41f36bd16c | ||
|
|
3af00e3aad | ||
|
|
a920e1fe80 | ||
|
|
7a1fb943de | ||
|
|
27655b80a5 | ||
|
|
1690888782 | ||
|
|
2ef51857b5 | ||
|
|
e7460cabc5 | ||
|
|
f588a2be99 | ||
|
|
3ab96bce79 | ||
|
|
49e72ab6bf | ||
|
|
da91dbf2d7 | ||
|
|
24974efe5f | ||
|
|
a25a63b316 | ||
|
|
335d981dee | ||
|
|
5e493288f0 | ||
|
|
60277b42d4 | ||
|
|
39e0999481 | ||
|
|
a5d4a1c5d1 | ||
|
|
754749ff4d | ||
|
|
295d790dab | ||
|
|
c20d156e19 | ||
|
|
a7315eeb12 | ||
|
|
8a0d844adb | ||
|
|
2574622760 | ||
|
|
cc5eb45624 | ||
|
|
9aac434f1a | ||
|
|
9ad4d52352 | ||
|
|
2131a724a6 | ||
|
|
3fa0cbdfe7 | ||
|
|
0584eeb643 | ||
|
|
c89c320ee9 | ||
|
|
2ee949830a | ||
|
|
1697a85de6 | ||
|
|
85868a322e | ||
|
|
a85684bb96 | ||
|
|
43b6c24919 | ||
|
|
c5863204c8 | ||
|
|
349d760a50 | ||
|
|
8374e410f4 | ||
|
|
3aec25bbdd | ||
|
|
92b6d309e4 | ||
|
|
aa0eee9812 | ||
|
|
89e48b0979 | ||
|
|
585eb0e0de | ||
|
|
58fba95c0f | ||
|
|
c650ae418d | ||
|
|
0ed3d3afa7 | ||
|
|
1df97c4106 | ||
|
|
99300a8715 | ||
|
|
5a54d537b5 | ||
|
|
20fbd266f4 | ||
|
|
a1abcff2d5 | ||
|
|
052c1362e0 | ||
|
|
30a41b59f4 | ||
|
|
7ae08dea69 | ||
|
|
457bfbf6d0 | ||
|
|
21ab3d159e | ||
|
|
749de1b0e9 | ||
|
|
5418ace2fc | ||
|
|
e54e865ce5 | ||
|
|
97cc8cce0d | ||
|
|
ee02691601 | ||
|
|
466ca12c91 | ||
|
|
b336512a5b | ||
|
|
cfcab79a6d | ||
|
|
2cc0e81445 | ||
|
|
408efdb631 | ||
|
|
df481cd2b5 | ||
|
|
f2f7928068 | ||
|
|
cb0f8c2001 | ||
|
|
829b00d3c8 | ||
|
|
5bbcda5b5f | ||
|
|
1b213dc31f | ||
|
|
bfe94e735a | ||
|
|
8993e48ae9 | ||
|
|
fda538ce92 | ||
|
|
e09d175fa8 | ||
|
|
e1e735ff46 | ||
|
|
179f3f1146 | ||
|
|
940af4b622 | ||
|
|
dedef13719 | ||
|
|
f2178a7548 | ||
|
|
537fa7b7ea | ||
|
|
e4c5cfba61 | ||
|
|
5b79b92566 | ||
|
|
c2c9f99c68 | ||
|
|
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 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ param_parser.go
|
||||
*.exe
|
||||
*.exe~
|
||||
.vscode
|
||||
.idea
|
||||
@@ -4,13 +4,14 @@ import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/dchest/captcha"
|
||||
@@ -276,7 +277,7 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
|
||||
//如果是小程序
|
||||
if authType == "weixinmini" || authType == "weixinapp" {
|
||||
appID := strings.Split(authSecret, ",")[0]
|
||||
if appID == "wx08a5c2a8581414ff" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
|
||||
if appID == "wxa4a76d7b4c88604e" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
|
||||
if user != nil {
|
||||
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), user.GetID(), 0, nil, "", "", "wx2bb99eb5d2c9b82c")
|
||||
if err != nil {
|
||||
@@ -475,3 +476,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
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package alipay
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/alipayapi"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthType = "alipaycode"
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
authprovider.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObj *Auther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObj = new(Auther)
|
||||
auth2.RegisterAuther(AuthType, AutherObj)
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("VerifySecret dummy:%s, code:%s", dummy, code)
|
||||
tokenInfo, err := api.AliPayAPI.SystemAuthToken(alipayapi.GrantTypeCode, code, "")
|
||||
if err == nil {
|
||||
userInfo, err2 := api.AliPayAPI.UserInfoShare(tokenInfo.AccessToken)
|
||||
if err = err2; err == nil {
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthType, api.AliPayAPI.GetAppID(), nil, userInfo.UserID, "", userInfo); err == nil {
|
||||
authBindEx.UserHint = &auth2.UserBasic{
|
||||
Name: userInfo.NickName,
|
||||
Avatar: userInfo.Avatar,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package dingding
|
||||
|
||||
const (
|
||||
AuthTypeStaff = "ddstaff" // 钉钉企业登录
|
||||
AuthTypeQRCode = "ddqrcode"
|
||||
)
|
||||
@@ -1,37 +0,0 @@
|
||||
package dingding
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type QRCodeAuther struct {
|
||||
authprovider.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObjQRCode *QRCodeAuther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObjQRCode = new(QRCodeAuther)
|
||||
auth2.RegisterAuther(AuthTypeQRCode, AutherObjQRCode)
|
||||
}
|
||||
|
||||
func (a *QRCodeAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("dingding qrcode VerifySecret code:%s", code)
|
||||
|
||||
userQRInfo, err := api.DingDingQRCodeAPI.GetUserInfoByCode(code)
|
||||
if err == nil {
|
||||
globals.SugarLogger.Debugf("dingding qrcode VerifySecret code:%s, userQRInfo:%s", code, utils.Format4Output(userQRInfo, false))
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthTypeQRCode, api.DingDingQRCodeAPI.GetAppID(), []string{AuthTypeStaff, AuthTypeQRCode}, userQRInfo.OpenID, userQRInfo.UnionID, userQRInfo); err == nil {
|
||||
authBindEx.UserHint = &auth2.UserBasic{
|
||||
Name: userQRInfo.Nickname,
|
||||
}
|
||||
}
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package dingding
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type StaffAuther struct {
|
||||
authprovider.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObjStaff *StaffAuther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObjStaff = new(StaffAuther)
|
||||
auth2.RegisterAuther(AuthTypeStaff, AutherObjStaff)
|
||||
}
|
||||
|
||||
func (a *StaffAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("dingding staff VerifySecret code:%s", code)
|
||||
|
||||
userID, err := api.DingDingAPI.GetUserID(code)
|
||||
if err == nil {
|
||||
userDetail, err2 := api.DingDingAPI.GetUserDetail(userID.UserID)
|
||||
if err = err2; err == nil {
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthTypeStaff, api.DingDingQRCodeAPI.GetAppID(), []string{AuthTypeStaff, AuthTypeQRCode}, userID.UserID, utils.Interface2String(userDetail["unionid"]), userDetail); err == nil {
|
||||
authBindEx.UserHint = &auth2.UserBasic{
|
||||
UserID2: userID.UserID,
|
||||
Mobile: utils.Interface2String(userDetail["mobile"]),
|
||||
Email: utils.Interface2String(userDetail["email"]),
|
||||
Name: utils.Interface2String(userDetail["name"]),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
|
||||
func (a *StaffAuther) GetUserType() (userType int8) {
|
||||
return model.UserTypeOperator
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package mobile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
aliyunsmsclient "github.com/KenmyZhang/aliyun-communicate"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthType = auth2.AuthTypeMobile
|
||||
TestVerifyCode = "123456"
|
||||
)
|
||||
|
||||
var (
|
||||
warningMap = map[string]int{
|
||||
"isv.AMOUNT_NOT_ENOUGH": 1,
|
||||
"isv.ACCOUNT_ABNORMAL": 1,
|
||||
"isv.OUT_OF_SERVICE": 1,
|
||||
"isv.DAY_LIMIT_CONTROL": 1,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ErrVerifyCodeIsWrong = errors.New("验证码错")
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
authprovider.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObj *Auther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObj = new(Auther)
|
||||
auth2.RegisterAuther(AuthType, AutherObj)
|
||||
}
|
||||
|
||||
// 特殊接口
|
||||
func (a *Auther) SendVerifyCode(mobileNumber string) (verifyCode string, err error) {
|
||||
verifyCode = a.GenerateVerifyCode(mobileNumber)
|
||||
smsClient := aliyunsmsclient.New("http://dysmsapi.aliyuncs.com/")
|
||||
response, err := smsClient.Execute(globals.AliKey, globals.AliSecret, mobileNumber, globals.SMSSignName, globals.SMSMobileVerifyTemplate, string(utils.MustMarshal(map[string]interface{}{
|
||||
"code": verifyCode,
|
||||
})))
|
||||
a.SaveVerifyCode(mobileNumber, verifyCode)
|
||||
if err == nil && response.Code == aliyunsmsclient.ResponseCodeOk {
|
||||
// a.SaveVerifyCode(mobileNumber, verifyCode)
|
||||
} else {
|
||||
if err == nil {
|
||||
if warningMap[response.Code] == 1 {
|
||||
globals.SugarLogger.Warnf("SendVerifyCode mobileNumber:%s failed with response:%s", mobileNumber, utils.Format4Output(response, false))
|
||||
} else {
|
||||
globals.SugarLogger.Infof("SendVerifyCode mobileNumber:%s failed with response:%s", mobileNumber, utils.Format4Output(response, false))
|
||||
}
|
||||
err = fmt.Errorf("发送短信出错:%s", response.Message)
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendVerifyCode mobileNumber:%s failed with error:%v", mobileNumber, err)
|
||||
}
|
||||
}
|
||||
return verifyCode, err
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(mobileNumber, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("VerifySecret mobileNumber:%s, code:%s", mobileNumber, code)
|
||||
|
||||
err = ErrVerifyCodeIsWrong
|
||||
if (code == auth2.InternalAuthSecret ||
|
||||
auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode) ||
|
||||
a.VerifyCode(mobileNumber, code) {
|
||||
err = nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 此函数为空
|
||||
func (a *Auther) AddAuthBind(authBindEx *auth2.AuthBindEx, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// 此函数为空
|
||||
func (a *Auther) UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package password
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthType = auth2.AuthTypePassword
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
authprovider.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObj *Auther
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUserAndPassNotMatch = errors.New("用户名密码不匹配")
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObj = new(Auther)
|
||||
auth2.RegisterAuther(AuthType, AutherObj)
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(userID, passMD5 string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("localpass VerifySecret userID:%s", userID)
|
||||
var authBind *model.AuthBind
|
||||
if authBind, err = dao.GetAuthBind(dao.GetDB(), model.AuthBindTypeAuth, AuthType, userID); err == nil {
|
||||
if err = a.checkPassword(authBind, passMD5); err == nil {
|
||||
authBindEx = &auth2.AuthBindEx{
|
||||
AuthBind: *authBind,
|
||||
}
|
||||
}
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
err = auth2.ErrUserAuthTypeNotExist
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
|
||||
// 特殊接口
|
||||
func (a *Auther) ChangePassword(userID, userName, oldPassMD5, newPassMD5 string) (err error) {
|
||||
var authBind *model.AuthBind
|
||||
db := dao.GetDB()
|
||||
salt := utils.GetUUID()
|
||||
encryptPwd := a.encryptPassword(newPassMD5, salt)
|
||||
if authBind, err = dao.GetAuthBind(db, model.AuthBindTypeAuth, AuthType, userID); err == nil {
|
||||
if err = a.checkPassword(authBind, oldPassMD5); err == nil || authBind.AuthSecret == "" { // 如果原密码为空,不判断原密码,代表重置密码
|
||||
_, err = dao.UpdateEntityLogically(db, authBind, map[string]interface{}{
|
||||
"AuthSecret": encryptPwd,
|
||||
"AuthSecret2": salt,
|
||||
}, userName, nil)
|
||||
}
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
err = a.AddAuthBind(&auth2.AuthBindEx{
|
||||
AuthBind: model.AuthBind{
|
||||
UserID: userID,
|
||||
Type: AuthType,
|
||||
AuthID: userID,
|
||||
AuthSecret: encryptPwd,
|
||||
AuthSecret2: salt,
|
||||
},
|
||||
}, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Auther) encryptPassword(password, salt string) string {
|
||||
return fmt.Sprintf("%x", sha1.Sum([]byte(password+salt)))
|
||||
}
|
||||
|
||||
func (a *Auther) checkPassword(authBind *model.AuthBind, passMD5 string) (err error) {
|
||||
if authBind.AuthSecret != a.encryptPassword(passMD5, authBind.AuthSecret2) {
|
||||
return ErrUserAndPassNotMatch
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package weixin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthTypeWeixin = "wxqrcode" // 微信扫码
|
||||
AuthTypeMP = "weixinsns" // 公众号
|
||||
AuthTypeWXNative = "wxnative" // 微信APP
|
||||
AuthTypeWxApp = "weixinapp" //app微信登录
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
authprovider.DefAuther
|
||||
authType string
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObjWX *Auther
|
||||
AutherObjMP *Auther
|
||||
AutherObjNative *Auther
|
||||
AutherObjApp *Auther
|
||||
)
|
||||
|
||||
var (
|
||||
ErrStateIsWrong = errors.New("登录state非法")
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObjWX = &Auther{
|
||||
authType: AuthTypeWeixin,
|
||||
}
|
||||
auth2.RegisterAuther(AuthTypeWeixin, AutherObjWX)
|
||||
|
||||
AutherObjMP = &Auther{
|
||||
authType: AuthTypeMP,
|
||||
}
|
||||
auth2.RegisterAuther(AuthTypeMP, AutherObjMP)
|
||||
|
||||
AutherObjNative = &Auther{
|
||||
authType: AuthTypeWXNative,
|
||||
}
|
||||
auth2.RegisterAuther(AuthTypeWXNative, AutherObjNative)
|
||||
|
||||
AutherObjApp = &Auther{
|
||||
authType: AuthTypeWxApp,
|
||||
}
|
||||
auth2.RegisterAuther(AuthTypeWxApp, AutherObjApp)
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(id, secret string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("weixin VerifySecret id:%s secret:%s", secret, secret)
|
||||
var openID, accessToken string
|
||||
if a.authType != AuthTypeWXNative {
|
||||
state := id
|
||||
code := secret
|
||||
if state == "" {
|
||||
token, err2 := a.getAPI().SNSRetrieveToken(code)
|
||||
if err = err2; err == nil {
|
||||
openID = token.OpenID
|
||||
accessToken = token.AccessToken
|
||||
}
|
||||
} else {
|
||||
err = ErrStateIsWrong
|
||||
}
|
||||
} else {
|
||||
openID = id
|
||||
accessToken = secret
|
||||
}
|
||||
if err == nil {
|
||||
wxUserinfo, err2 := a.getAPI().SNSGetUserInfo(accessToken, openID)
|
||||
if err = err2; err == nil {
|
||||
if authBindEx, err = a.UnionFindAuthBind(a.authType, a.getAPI().GetAppID(), []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini, AuthTypeWXNative, AuthTypeWxApp}, wxUserinfo.OpenID, wxUserinfo.UnionID, wxUserinfo); err == nil {
|
||||
authBindEx.UserHint = &auth2.UserBasic{
|
||||
Name: wxUserinfo.NickName,
|
||||
Avatar: wxUserinfo.HeadImgURL,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
|
||||
func (a *Auther) getAPI() *weixinapi.API {
|
||||
if a.authType == AuthTypeWeixin {
|
||||
return api.WeixinPageAPI
|
||||
}
|
||||
if a.authType == AuthTypeWxApp {
|
||||
return api.WeixinApp
|
||||
}
|
||||
return api.WeixinAPI
|
||||
}
|
||||
|
||||
func (a *Auther) GetUserType() (userType int8) {
|
||||
return model.UserTypeStoreBoss
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package weixin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthTypeMini = "weixinmini" // 小程序
|
||||
)
|
||||
|
||||
type MiniAuther struct {
|
||||
authprovider.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
ErrAuthTypeShouldBeMini = errors.New("当前操作要求是小程序登录方式")
|
||||
)
|
||||
|
||||
var (
|
||||
AutherObjMini *MiniAuther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObjMini = new(MiniAuther)
|
||||
auth2.RegisterAuther(AuthTypeMini, AutherObjMini)
|
||||
}
|
||||
|
||||
func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("weixin mini VerifySecret jsCode:%s", jsCode)
|
||||
|
||||
appID, jsCode := SplitJsCode(jsCode)
|
||||
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
|
||||
if err == nil {
|
||||
sessionKey := sessionInfo.SessionKey
|
||||
sessionInfo.SessionKey = ""
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthTypeMini, getWxApp(appID).GetAppID(), []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini, AuthTypeWXNative}, sessionInfo.OpenID, sessionInfo.UnionID, sessionInfo); err == nil {
|
||||
authBindEx.UserData = sessionKey
|
||||
}
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
|
||||
// 特殊接口
|
||||
func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData, iv string) (decryptedDataBase64 string, err error) {
|
||||
globals.SugarLogger.Debugf("weixin mini DecryptData jsCode:%s, encryptedData:%s, iv:%s", jsCode, encryptedData, iv)
|
||||
var sessionKey string
|
||||
appID, jsCode := SplitJsCode(jsCode)
|
||||
if jsCode != "" {
|
||||
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
|
||||
if err == nil {
|
||||
if authBindEx, err := a.UnionFindAuthBind(AuthTypeMini, getWxApp(appID).GetAppID(), []string{AuthTypeMini}, sessionInfo.OpenID, "", nil); err == nil {
|
||||
if authBindEx.UserID != authInfo.GetID() {
|
||||
return "", fmt.Errorf("jsCode与token不匹配")
|
||||
}
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
sessionKey = sessionInfo.SessionKey
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
if authInfo.AuthBindInfo.Type != AuthTypeMini {
|
||||
return "", ErrAuthTypeShouldBeMini
|
||||
}
|
||||
sessionKey = authInfo.AuthBindInfo.UserData.(string)
|
||||
}
|
||||
// decryptedData, err := ProxySNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
|
||||
decryptedData, err := weixinapi.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
authInfo.AuthBindInfo.UserData = sessionKey
|
||||
return string(decryptedData), nil
|
||||
}
|
||||
|
||||
func (a *MiniAuther) GetUserType() (userType int8) {
|
||||
return model.UserTypeStoreBoss
|
||||
}
|
||||
|
||||
func getWxApp(appID string) (miniApi *weixinapi.API) {
|
||||
miniApi = api.WeixinMiniAPI
|
||||
if len(appID) > 0 && appID == api.WeixinMiniAppID2 {
|
||||
miniApi = api.WeixinMiniAPI2
|
||||
}
|
||||
return miniApi
|
||||
}
|
||||
|
||||
func SplitJsCode(jsCode string) (appID, realJsCode string) {
|
||||
list := strings.Split(jsCode, ",")
|
||||
if len(list) == 2 {
|
||||
appID = list[0]
|
||||
realJsCode = list[1]
|
||||
} else if len(list) == 1 {
|
||||
realJsCode = jsCode
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SplitJsCode abnormal jsCode:%s", jsCode)
|
||||
}
|
||||
return appID, realJsCode
|
||||
}
|
||||
|
||||
func ComposeJsCode(appID, jsCode string) (composedCode string) {
|
||||
composedCode = strings.Join([]string{
|
||||
appID,
|
||||
jsCode,
|
||||
}, ",")
|
||||
return composedCode
|
||||
}
|
||||
|
||||
// func ProxySNSCode2Session(jsCode string) (sessionInfo *weixinapi.SessionInfo, err error) {
|
||||
// miniApi := api.WeixinMiniAPI
|
||||
// list := strings.Split(jsCode, ",")
|
||||
// if len(list) >= 2 && len(list[0]) == len("wx4b5930c13f8b1170") {
|
||||
// if list[0] == api.WeixinMiniAppID2 {
|
||||
// miniApi = api.WeixinMiniAPI2
|
||||
// }
|
||||
// miniApi = getWxApp(list[0])
|
||||
// jsCode = strings.Join(list[1:], ",")
|
||||
// }
|
||||
// sessionInfo, err = miniApi.SNSCode2Session(jsCode)
|
||||
// return sessionInfo, err
|
||||
// }
|
||||
|
||||
// func ProxySNSDecodeMiniProgramData(encryptedData, sessionKey, iv string) (decryptedData []byte, err error) {
|
||||
// globals.SugarLogger.Debugf("ProxySNSDecodeMiniProgramData, encryptedData:%s, sessionKey:%s, iv:%s", encryptedData, sessionKey, iv)
|
||||
// decryptedData, err = api.WeixinMiniAPI.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
|
||||
// return decryptedData, err
|
||||
// }
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/authz"
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
func GetRoleDescription(name string, storeID int) (description string) {
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
package casbinauth
|
||||
|
||||
import (
|
||||
jxmodel "git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/casbin/casbin/model"
|
||||
"github.com/casbin/casbin/persist"
|
||||
)
|
||||
|
||||
type Adapter struct {
|
||||
}
|
||||
|
||||
// finalizer is the destructor for Adapter.
|
||||
func finalizer(a *Adapter) {
|
||||
}
|
||||
|
||||
func NewAdapter() *Adapter {
|
||||
return &Adapter{}
|
||||
}
|
||||
|
||||
func loadPolicyLine(line jxmodel.CasbinRule, model model.Model) {
|
||||
lineText := line.PType
|
||||
if line.V0 != "" {
|
||||
lineText += ", " + line.V0
|
||||
}
|
||||
if line.V1 != "" {
|
||||
lineText += ", " + line.V1
|
||||
}
|
||||
if line.V2 != "" {
|
||||
lineText += ", " + line.V2
|
||||
}
|
||||
if line.V3 != "" {
|
||||
lineText += ", " + line.V3
|
||||
}
|
||||
if line.V4 != "" {
|
||||
lineText += ", " + line.V4
|
||||
}
|
||||
if line.V5 != "" {
|
||||
lineText += ", " + line.V5
|
||||
}
|
||||
|
||||
persist.LoadPolicyLine(lineText, model)
|
||||
}
|
||||
|
||||
func (a *Adapter) LoadPolicy(model model.Model) error {
|
||||
var lines []jxmodel.CasbinRule
|
||||
o := orm.NewOrm()
|
||||
_, err := o.QueryTable("casbin_rule").Limit(-1).All(&lines)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, line := range lines {
|
||||
loadPolicyLine(line, model)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func savePolicyLine(ptype string, rule []string) jxmodel.CasbinRule {
|
||||
line := jxmodel.CasbinRule{}
|
||||
|
||||
line.PType = ptype
|
||||
if len(rule) > 0 {
|
||||
line.V0 = rule[0]
|
||||
}
|
||||
if len(rule) > 1 {
|
||||
line.V1 = rule[1]
|
||||
}
|
||||
if len(rule) > 2 {
|
||||
line.V2 = rule[2]
|
||||
}
|
||||
if len(rule) > 3 {
|
||||
line.V3 = rule[3]
|
||||
}
|
||||
if len(rule) > 4 {
|
||||
line.V4 = rule[4]
|
||||
}
|
||||
if len(rule) > 5 {
|
||||
line.V5 = rule[5]
|
||||
}
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
func (a *Adapter) clearAll(o orm.Ormer) (err error) {
|
||||
_, err = o.Raw(`
|
||||
DELETE t1
|
||||
FROM casbin_rule t1
|
||||
`).Exec()
|
||||
return err
|
||||
}
|
||||
|
||||
// SavePolicy saves policy to database.
|
||||
func (a *Adapter) SavePolicy(model model.Model) error {
|
||||
globals.SugarLogger.Debugf("SavePolicy")
|
||||
o := orm.NewOrm()
|
||||
|
||||
a.clearAll(o)
|
||||
var lines []jxmodel.CasbinRule
|
||||
|
||||
for ptype, ast := range model["p"] {
|
||||
for _, rule := range ast.Policy {
|
||||
line := savePolicyLine(ptype, rule)
|
||||
lines = append(lines, line)
|
||||
}
|
||||
}
|
||||
|
||||
for ptype, ast := range model["g"] {
|
||||
for _, rule := range ast.Policy {
|
||||
line := savePolicyLine(ptype, rule)
|
||||
lines = append(lines, line)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := o.InsertMulti(len(lines), lines)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddPolicy adds a policy rule to the storage.
|
||||
func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) error {
|
||||
o := orm.NewOrm()
|
||||
line := savePolicyLine(ptype, rule)
|
||||
_, err := o.Insert(&line)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemovePolicy removes a policy rule from the storage.
|
||||
func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string) error {
|
||||
o := orm.NewOrm()
|
||||
line := savePolicyLine(ptype, rule)
|
||||
_, err := o.Delete(&line, "p_type", "v0", "v1", "v2", "v3", "v4", "v5")
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveFilteredPolicy removes policy rules that match the filter from the storage.
|
||||
func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error {
|
||||
line := jxmodel.CasbinRule{}
|
||||
|
||||
line.PType = ptype
|
||||
filter := []string{}
|
||||
filter = append(filter, "p_type")
|
||||
if fieldIndex <= 0 && 0 < fieldIndex+len(fieldValues) {
|
||||
line.V0 = fieldValues[0-fieldIndex]
|
||||
filter = append(filter, "v0")
|
||||
}
|
||||
if fieldIndex <= 1 && 1 < fieldIndex+len(fieldValues) {
|
||||
line.V1 = fieldValues[1-fieldIndex]
|
||||
filter = append(filter, "v1")
|
||||
}
|
||||
if fieldIndex <= 2 && 2 < fieldIndex+len(fieldValues) {
|
||||
line.V2 = fieldValues[2-fieldIndex]
|
||||
filter = append(filter, "v2")
|
||||
}
|
||||
if fieldIndex <= 3 && 3 < fieldIndex+len(fieldValues) {
|
||||
line.V3 = fieldValues[3-fieldIndex]
|
||||
filter = append(filter, "v3")
|
||||
}
|
||||
if fieldIndex <= 4 && 4 < fieldIndex+len(fieldValues) {
|
||||
line.V4 = fieldValues[4-fieldIndex]
|
||||
filter = append(filter, "v4")
|
||||
}
|
||||
if fieldIndex <= 5 && 5 < fieldIndex+len(fieldValues) {
|
||||
line.V5 = fieldValues[5-fieldIndex]
|
||||
filter = append(filter, "v5")
|
||||
}
|
||||
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Delete(&line, filter...)
|
||||
return err
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package casbinauth
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/authz"
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
"github.com/casbin/casbin"
|
||||
"github.com/casbin/casbin/errors"
|
||||
)
|
||||
|
||||
type CasbinAuthz struct {
|
||||
enforcer *casbin.SyncedEnforcer
|
||||
}
|
||||
|
||||
func New(modelFile string) (authObj authz.IAuthz, err error) {
|
||||
obj := &CasbinAuthz{}
|
||||
obj.enforcer, err = casbin.NewSyncedEnforcer(modelFile, NewAdapter())
|
||||
return obj, err
|
||||
}
|
||||
|
||||
func (c *CasbinAuthz) AddRole4User(userID string, r *authz.RoleInfo) (err error) {
|
||||
_, err = c.enforcer.AddRoleForUser(userID, r.GetFullName())
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CasbinAuthz) DeleteRole4User(userID string, r *authz.RoleInfo) (err error) {
|
||||
_, err = c.enforcer.DeleteRoleForUser(userID, r.GetFullName())
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CasbinAuthz) GetUserRoleList(userID string) (roleList []*authz.RoleInfo, err error) {
|
||||
roleNameList, err := c.enforcer.GetRolesForUser(userID)
|
||||
if err == nil && len(roleNameList) > 0 {
|
||||
roleList = autils.FullRoleName2RoleList(roleNameList)
|
||||
}
|
||||
return roleList, err
|
||||
}
|
||||
|
||||
func (c *CasbinAuthz) GetRoleUserList(r *authz.RoleInfo) (userIDList []string, err error) {
|
||||
// globals.SugarLogger.Debug(roleFullName)
|
||||
userIDList, err = c.enforcer.GetUsersForRole(r.GetFullName())
|
||||
if err == errors.ERR_NAME_NOT_FOUND {
|
||||
err = nil
|
||||
}
|
||||
return userIDList, err
|
||||
}
|
||||
|
||||
// func (c *CasbinAuthz) GetAllRoleList() (roleList []*authz.RoleInfo) {
|
||||
// return authz.FullRoleName2RoleList(c.enforcer.GetAllRoles())
|
||||
// }
|
||||
@@ -1,128 +0,0 @@
|
||||
package cs
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/weimobapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
minCSOrderPayment = 0 // 供货订单的最小金额(单位为元)
|
||||
maxUnitPrice = 3000 // 为防止误填单价,限制单价最高(单位为分)
|
||||
)
|
||||
|
||||
func OnCallbackMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
|
||||
orderID := utils.Int64ToStr(msg.OrderNo)
|
||||
jxutils.CallMsgHandler(func() {
|
||||
response = onOrderMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDWSC))
|
||||
return response
|
||||
}
|
||||
|
||||
func onOrderMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
|
||||
globals.SugarLogger.Debugf("onOrderMsg:%s", utils.Format4Output(msg, true))
|
||||
if msg.Event == weimobapi.MsgEventOrderStatusChange {
|
||||
if utils.ForceInterface2Int64(msg.MsgBody["orderStatus"]) == weimobapi.MsgOrderStatusFinished {
|
||||
if orderDetail, err := api.WeimobAPI.QueryOrderDetail2(msg.OrderNo, false); err == nil {
|
||||
if orderDetail.OrderStatus == weimobapi.OrderStatusFinished && orderDetail.PaymentAmount >= minCSOrderPayment {
|
||||
changeStoreSkusByOrder(orderDetail)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onOrderMsg order:%s failed with err:%v", msg.OrderNo, err)
|
||||
response = weimobapi.Err2CallbackResponse(err, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
func changeStoreSkusByOrder(order *weimobapi.OrderDetail) {
|
||||
globals.SugarLogger.Debugf("changeStoreSkusByOrder order:%s", utils.Format4Output(order, true))
|
||||
receiverMobile := order.DeliveryDetail.LogisticsDeliveryDetail.ReceiverMobile
|
||||
ctx := jxcontext.NewWithUserName(nil, utils.LimitStringLen(utils.Int64ToStr(order.OrderNo), 32), nil, nil)
|
||||
if storeList, err := GetStoreList4Mobile(dao.GetDB(), []string{receiverMobile}); err == nil {
|
||||
if len(storeList) >= 1 {
|
||||
var skuBindInfos []*cms.StoreSkuBindInfo
|
||||
storeID := storeList[0].ID
|
||||
globals.SugarLogger.Debugf("changeStoreSkusByOrder storeID:%d", storeID)
|
||||
for _, v := range order.ItemList {
|
||||
nameID := int(utils.Str2Int64WithDefault(v.SkuCode, 0))
|
||||
unitPrice := v.CostPrice
|
||||
if nameID > 0 && (unitPrice > 0 && unitPrice < maxUnitPrice) {
|
||||
skuBindInfos = append(skuBindInfos, &cms.StoreSkuBindInfo{
|
||||
StoreID: storeID,
|
||||
NameID: nameID,
|
||||
UnitPrice: int(jxutils.StandardPrice2Int(unitPrice)),
|
||||
IsFocus: 1,
|
||||
IsSale: 1,
|
||||
})
|
||||
} else {
|
||||
globals.SugarLogger.Infof("[运营],微商城订单:%d,商品:%s没有设置正确的SkuName编码或单价,当前商家编码:%s,市场价:%s", order.OrderNo, v.SkuNum, v.SkuCode, jxutils.IntPrice2StandardString(jxutils.StandardPrice2Int(unitPrice)))
|
||||
}
|
||||
}
|
||||
if len(skuBindInfos) > 0 {
|
||||
var nameIDs []int
|
||||
for _, v := range skuBindInfos {
|
||||
nameIDs = append(nameIDs, v.NameID)
|
||||
}
|
||||
if skuNamesInfo, err := cms.GetSkuNames(ctx, "", false, false, map[string]interface{}{
|
||||
"nameIDs": string(utils.MustMarshal(nameIDs)),
|
||||
}, 0, 0); err == nil {
|
||||
for _, skuName := range skuNamesInfo.SkuNames {
|
||||
if skuName.Status != model.SkuStatusNormal {
|
||||
cms.UpdateSkuName(ctx, skuName.ID, map[string]interface{}{
|
||||
"status": model.SkuStatusNormal,
|
||||
}, false)
|
||||
}
|
||||
for _, sku := range skuName.Skus {
|
||||
if sku.Status != model.SkuStatusNormal {
|
||||
cms.UpdateSku(ctx, sku.ID, map[string]interface{}{
|
||||
"status": model.SkuStatusNormal,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cms.UpdateStoreSkus(ctx, 0, storeID, skuBindInfos, true, true)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("changeStoreSkusByOrder orderID:%d, storeID:%d is empty", order.OrderNo, storeID)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Infof("[运营],微商城订单:%d,手机:%s找不到唯一一个本地门店%d", order.OrderNo, receiverMobile, len(storeList))
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("changeStoreSkusByOrder orderNo:%d, receiverMobile:%s failed with err:%v", order.OrderNo, receiverMobile, err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetStoreList4Mobile(db *dao.DaoDB, mobileList []string) (storeList []*model.Store, err error) {
|
||||
sql := `
|
||||
SELECT t1.*
|
||||
FROM store t1
|
||||
WHERE t1.deleted_at = ? /*AND t1.change_price_type = ?*/`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
// model.StoreChangePriceTypeBossDisabled,
|
||||
}
|
||||
if len(mobileList) > 0 {
|
||||
questionMarks := dao.GenQuestionMarks(len(mobileList))
|
||||
sql += " AND (t1.tel1 IN (" + questionMarks + ") OR t1.tel2 IN (" + questionMarks + `)
|
||||
OR (SELECT
|
||||
COUNT(*)
|
||||
FROM casbin_rule t2
|
||||
JOIN user t3 ON t3.user_id = t2.v0 AND t3.mobile IN (` + questionMarks + `)
|
||||
WHERE t2.v1 = CONCAT(?, t1.id)
|
||||
) > 0)
|
||||
`
|
||||
sqlParams = append(sqlParams, mobileList, mobileList, mobileList, autils.NewStoreBossRole(-1).GetFullName())
|
||||
}
|
||||
err = dao.GetRows(db, &storeList, sql, sqlParams...)
|
||||
return storeList, err
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package cs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestGetStoreList4Mobile(t *testing.T) {
|
||||
storeList, err := GetStoreList4Mobile(dao.GetDB(), []string{"18180948107"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(storeList, false))
|
||||
t.Log(len(storeList))
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -65,15 +65,15 @@ func GetDB() *DaoDB {
|
||||
return &DaoDB{Db: orm.NewOrm()}
|
||||
}
|
||||
|
||||
func Begin(db *DaoDB) (err error) {
|
||||
func Begin(db *DaoDB) (txDB orm.TxOrmer, err error) {
|
||||
if db.transactionLevel == 0 {
|
||||
err = db.Db.Begin()
|
||||
txDB, err = db.Db.Begin()
|
||||
if err == nil {
|
||||
db.startWatchTransaction()
|
||||
}
|
||||
}
|
||||
db.transactionLevel++
|
||||
return err
|
||||
return txDB, err
|
||||
}
|
||||
|
||||
func (db *DaoDB) startWatchTransaction() {
|
||||
@@ -93,11 +93,11 @@ func (db *DaoDB) stopWatchTransaction() {
|
||||
}
|
||||
}
|
||||
|
||||
func Commit(db *DaoDB) (err error) {
|
||||
func Commit(db *DaoDB, txDB orm.TxOrmer) (err error) {
|
||||
if db.transactionLevel == 1 {
|
||||
db.stopWatchTransaction()
|
||||
|
||||
err = db.Db.Commit()
|
||||
err = txDB.Commit()
|
||||
//err = db.Db.Commit()
|
||||
db.transactionLevel = 0
|
||||
} else if db.transactionLevel > 1 {
|
||||
db.transactionLevel--
|
||||
@@ -105,11 +105,11 @@ func Commit(db *DaoDB) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func Rollback(db *DaoDB) (err error) {
|
||||
func Rollback(db *DaoDB, txDB orm.TxOrmer) (err error) {
|
||||
if db.transactionLevel > 0 {
|
||||
db.stopWatchTransaction()
|
||||
|
||||
err = db.Db.Rollback()
|
||||
err = txDB.Rollback()
|
||||
//err = db.Db.Rollback()
|
||||
}
|
||||
db.transactionLevel = 0
|
||||
return err
|
||||
@@ -139,6 +139,31 @@ func GetRow(db *DaoDB, inPtr interface{}, sql string, values ...interface{}) (er
|
||||
return err
|
||||
}
|
||||
|
||||
func GetRowTx(txDB orm.TxOrmer, inPtr interface{}, sql string, values ...interface{}) (err error) {
|
||||
if txDB == nil {
|
||||
return
|
||||
}
|
||||
if !useGetRowsWhenGetRow { // beego QueryRow有bug,嵌入的struct不能正常绑定
|
||||
err = txDB.Raw(sql, values).QueryRow(inPtr)
|
||||
//err = db.Db.Raw(sql, values).QueryRow(inPtr)
|
||||
} else {
|
||||
typeInfo := reflect.TypeOf(inPtr)
|
||||
if typeInfo.Kind() != reflect.Ptr {
|
||||
return errors.New("inPtr must be ptr")
|
||||
}
|
||||
slice := reflect.New(reflect.SliceOf(typeInfo.Elem()))
|
||||
if err = GetRowsTx(txDB, slice.Interface(), sql, values...); err == nil {
|
||||
slice = slice.Elem()
|
||||
if slice.Len() > 0 {
|
||||
reflect.ValueOf(inPtr).Elem().Set(slice.Index(0))
|
||||
} else {
|
||||
return orm.ErrNoRows
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetRows(db *DaoDB, inPtr interface{}, sql string, values ...interface{}) (err error) {
|
||||
if db == nil {
|
||||
db = GetDB()
|
||||
@@ -147,6 +172,15 @@ func GetRows(db *DaoDB, inPtr interface{}, sql string, values ...interface{}) (e
|
||||
return err
|
||||
}
|
||||
|
||||
func GetRowsTx(txDB orm.TxOrmer, inPtr interface{}, sql string, values ...interface{}) (err error) {
|
||||
if txDB == nil {
|
||||
return
|
||||
}
|
||||
_, err = txDB.Raw(sql, values).QueryRows(inPtr)
|
||||
//_, err = db.Db.Raw(sql, values).QueryRows(inPtr)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetEntity(db *DaoDB, item interface{}, cols ...string) (err error) {
|
||||
if db == nil {
|
||||
db = GetDB()
|
||||
@@ -178,6 +212,27 @@ func CreateEntity(db *DaoDB, item interface{}) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateEntityTx(txDB orm.TxOrmer, item interface{}, cols ...string) (num int64, err error) {
|
||||
if txDB == nil {
|
||||
return
|
||||
}
|
||||
num, err = txDB.Update(item, cols...)
|
||||
if err != nil && !IsDuplicateError(err) {
|
||||
globals.SugarLogger.Errorf("UpdateEntity %s failed with error:%v", reflect.TypeOf(item).Name(), err)
|
||||
}
|
||||
return num, err
|
||||
}
|
||||
|
||||
func CreateEntityTx(txDB orm.TxOrmer, item interface{}) (err error) {
|
||||
if txDB == nil {
|
||||
return
|
||||
}
|
||||
if _, err = txDB.Insert(item); err != nil && !IsDuplicateError(err) {
|
||||
globals.SugarLogger.Errorf("CreateEntity %s failed with error:%v", reflect.TypeOf(item).Name(), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// InsertMulti执行成功后ID不会改写成正确的(象Insert一样)
|
||||
func CreateMultiEntities(db *DaoDB, item interface{}) (err error) {
|
||||
if db == nil {
|
||||
@@ -208,6 +263,18 @@ func DeleteEntity(db *DaoDB, item interface{}, cols ...string) (num int64, err e
|
||||
return num, err
|
||||
}
|
||||
|
||||
func DeleteEntityTx(txDB orm.TxOrmer, item interface{}, cols ...string) (num int64, err error) {
|
||||
if txDB == nil {
|
||||
return
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
num, err = txDB.Delete(item, cols...)
|
||||
//num, err = db.Db.Delete(item, cols...)
|
||||
return err
|
||||
}, reflect.TypeOf(item).Name())
|
||||
return num, err
|
||||
}
|
||||
|
||||
func ExecuteSQL(db *DaoDB, sql string, params ...interface{}) (num int64, err error) {
|
||||
if db == nil {
|
||||
db = GetDB()
|
||||
@@ -230,3 +297,11 @@ func GetLastTotalRowCount(db *DaoDB) int {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetLastTotalRowCountTx(txDB orm.TxOrmer) int {
|
||||
countInfo := &struct{ Ct int }{}
|
||||
if err := GetRowTx(txDB, countInfo, "SELECT FOUND_ROWS() ct"); err == nil {
|
||||
return countInfo.Ct
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
91
business/dao/dao_print.go
Normal file
91
business/dao/dao_print.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
// QueryUserPrinter 查询用户打印机
|
||||
func QueryUserPrinter(userId, printNo string) (*model.Printer, error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM printer
|
||||
WHERE 1 = 1 AND deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
|
||||
if printNo != "" {
|
||||
sql += " AND print_no = ?"
|
||||
sqlParams = append(sqlParams, printNo)
|
||||
}
|
||||
if userId != "" {
|
||||
sql += " AND user_id = ?"
|
||||
sqlParams = append(sqlParams, userId)
|
||||
}
|
||||
var printer = &model.Printer{}
|
||||
err := GetRow(GetDB(), &printer, sql, sqlParams)
|
||||
return printer, err
|
||||
}
|
||||
|
||||
func GetPrinters(db *DaoDB, appID int, printNo string, status, statusNeq int) (printers []*model.Printer, err error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM printer
|
||||
WHERE 1 = 1 AND deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if appID != 0 {
|
||||
sql += " AND app_id = ?"
|
||||
sqlParams = append(sqlParams, appID)
|
||||
}
|
||||
if printNo != "" {
|
||||
sql += " AND print_no = ?"
|
||||
sqlParams = append(sqlParams, printNo)
|
||||
}
|
||||
if status != 0 {
|
||||
sql += " AND status = ?"
|
||||
sqlParams = append(sqlParams, status)
|
||||
}
|
||||
if statusNeq != 0 {
|
||||
sql += " AND status <> ?"
|
||||
sqlParams = append(sqlParams, statusNeq)
|
||||
}
|
||||
err = GetRows(db, &printers, sql, sqlParams)
|
||||
|
||||
globals.SugarLogger.Debugf("======printers==== %s", utils.Format4Output(printers, false))
|
||||
return printers, err
|
||||
}
|
||||
|
||||
func GetPrintMsgs(db *DaoDB, printNo, msgID string, status, statusNeq int) (printMsgs []*model.PrintMsg, err error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM print_msg
|
||||
WHERE 1 = 1 AND deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if status != model.PrintMsgAll {
|
||||
sql += " AND status = ?"
|
||||
sqlParams = append(sqlParams, status)
|
||||
}
|
||||
if statusNeq != model.PrintMsgAll {
|
||||
sql += " AND status <> ?"
|
||||
sqlParams = append(sqlParams, statusNeq)
|
||||
}
|
||||
if printNo != "" {
|
||||
sql += " AND print_no = ?"
|
||||
sqlParams = append(sqlParams, printNo)
|
||||
}
|
||||
if msgID != "" {
|
||||
sql += " AND msg_id = ?"
|
||||
sqlParams = append(sqlParams, msgID)
|
||||
}
|
||||
err = GetRows(db, &printMsgs, sql, sqlParams)
|
||||
return printMsgs, err
|
||||
}
|
||||
25
business/dao/dao_print_setting.go
Normal file
25
business/dao/dao_print_setting.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func GetPrintSetting(printNo string) (*model.PrintSettingObj, error) {
|
||||
sql := ` SELECT * FROM print_setting WHERE print_no = ? and deleted_at = ? `
|
||||
sqlParams := []interface{}{
|
||||
printNo,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
|
||||
var printSetting *model.PrintSetting
|
||||
if err := GetRow(GetDB(), &printSetting, sql, sqlParams...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if printSetting == nil {
|
||||
return nil, errors.New("数据查询异常")
|
||||
}
|
||||
|
||||
return model.UnMarshalString2Json(printSetting)
|
||||
}
|
||||
34
business/dao/dao_print_temp.go
Normal file
34
business/dao/dao_print_temp.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
// SelectUserDefaultTemp 查询用户默认模板
|
||||
func SelectUserDefaultTemp(userId string, tempType string) (*model.SystemTemp, bool, error) {
|
||||
var result *model.SystemTemp
|
||||
if err := GetRow(GetDB(), &result, `SELECT * FROM system_temp WHERE user_id = ? AND temp_type = ? AND is_use = ? AND deleted_at = ? ORDER BY created_at desc `, []interface{}{userId, tempType, 1, utils.DefaultTimeValue}...); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return result, true, nil
|
||||
}
|
||||
|
||||
// QuerySystemTemp 查询系统模板
|
||||
func QuerySystemTemp() (*model.SystemTemp, error) {
|
||||
var result []*model.SystemTemp
|
||||
if err := GetRows(GetDB(), &result, `SELECT * FROM system_temp WHERE user_id = ? AND temp_type = ? AND is_use = ? AND deleted_at = ? ORDER BY created_at desc `, []interface{}{"system_user", "user_store", 1, utils.DefaultTimeValue}...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(result) > 0 {
|
||||
return result[0], nil
|
||||
}
|
||||
return nil, errors.New("模板获取异常")
|
||||
}
|
||||
|
||||
// AddTemp 添加模板数据
|
||||
func AddTemp(param *model.SystemTemp) error {
|
||||
return CreateEntity(GetDB(), param)
|
||||
}
|
||||
19
business/dao/dao_user_test.go
Normal file
19
business/dao/dao_user_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetUsers(t *testing.T) {
|
||||
aa := "{\"title\":\"<center><b>京西菜市</b></center><br><center>手机买菜上京西</center><br><center>极速到家送惊喜</center><br>--------------------------------<br>\",\"divider\":\"--------------------------------<br>\",\"payOrderTime\":\"<left>下单时间:%s</left>\",\"trySendTime\":\"<left>预计送达时间:%s</left>\",\"consigneeName\":\"<left>客户名称:%s</left>\",\"consigneeMobile\":\"<left>客户电话:%s</left>\",\"consigneeAddress\":\"<left>客户地址:%s</left>\",\"buyerComment\":\"<left>客户备注:%s</left>\",\"qrcOrder\":\"<qrl>%s</qrl>\",\"goodsListDetail\":\"商品列表:<br>品名 数量 单价 小计<br>--------------------------------<br>\",\"skuName\":\"<b>%s</b><br>\",\"skuNumber\":\"<b>x%s</b>\",\"skuPrice\":\"<b>¥%s</b>\",\"skuAllPrice\":\"<b>¥%s</b>\",\"skuUpc\":\"upc码: %s<br>\",\"allSkuTypeCount\":\"<br><br><b>共 %s 种\",\"allSkuCount\":\" %s 件商品</b><br>\",\"storeName\":\"<center><b>商品质量问题请联系:</b></center><br><center><b>%s:\",\"storeTel\":\"%s</b></center><br><br>更多信息请关注官方微信:\",\"officialName\":\"<b>%s</b><br><br><br>--------------------------------<br>--------------------------------<br><br>\"}"
|
||||
|
||||
conte := make(map[string]string, 0)
|
||||
|
||||
if err := json.Unmarshal([]byte(aa), &conte); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log(utils.Format4Output(conte, false))
|
||||
}
|
||||
272
business/dao/event.go
Normal file
272
business/dao/event.go
Normal file
@@ -0,0 +1,272 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
type OperateEventExt struct {
|
||||
model.OperateEvent
|
||||
Detail []*model.OperateEventDetail `json:"detail"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func DeleteOperateEventDetail(db *DaoDB, deleteTime time.Time) (err error) {
|
||||
sql := `
|
||||
DELETE FROM a
|
||||
USING operate_event_detail a,operate_event b
|
||||
WHERE a.access_uuid = b.access_uuid
|
||||
AND b.created_at < ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
deleteTime,
|
||||
}
|
||||
_, err = ExecuteSQL(db, sql, sqlParams...)
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteOperateEvent(db *DaoDB, deleteTime time.Time) (err error) {
|
||||
sql := `
|
||||
DELETE FROM operate_event
|
||||
WHERE created_at < ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
deleteTime,
|
||||
}
|
||||
_, err = ExecuteSQL(db, sql, sqlParams...)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetOperateEvents(db *DaoDB, name string, apiFunctions []string, operateTypes, skuIDs, storeIDs []int, fromTime, toTime time.Time, keyword string, errType, offset, pageSize int) (operateEventExt []*OperateEventExt, totalCount int, err error) {
|
||||
sql := `
|
||||
SELECT SQL_CALC_FOUND_ROWS DISTINCT a.*, c.name
|
||||
FROM operate_event a
|
||||
`
|
||||
if len(operateTypes) > 0 || len(skuIDs) > 0 || len(storeIDs) > 0 || keyword != "" {
|
||||
sql += " LEFT JOIN operate_event_detail b ON a.access_uuid = b.access_uuid"
|
||||
}
|
||||
sql += `
|
||||
LEFT JOIN user c ON c.user_id = a.user_id
|
||||
WHERE 1=1
|
||||
`
|
||||
sqlParams := []interface{}{}
|
||||
if errType == 1 {
|
||||
sql += " AND a.err_msg = ''"
|
||||
}
|
||||
if errType == -1 {
|
||||
sql += " AND a.err_msg <> ''"
|
||||
}
|
||||
if name != "" {
|
||||
sql += " AND c.name LIKE ?"
|
||||
sqlParams = append(sqlParams, "%"+name+"%")
|
||||
}
|
||||
if !utils.IsTimeZero(fromTime) {
|
||||
sql += " AND a.created_at >= ?"
|
||||
sqlParams = append(sqlParams, fromTime)
|
||||
}
|
||||
if !utils.IsTimeZero(toTime) {
|
||||
sql += " AND a.created_at <= ?"
|
||||
sqlParams = append(sqlParams, toTime)
|
||||
}
|
||||
if len(apiFunctions) > 0 {
|
||||
sql += " AND a.api_function IN (" + GenQuestionMarks(len(apiFunctions)) + ")"
|
||||
sqlParams = append(sqlParams, apiFunctions)
|
||||
}
|
||||
if len(operateTypes) > 0 {
|
||||
sql += " AND b.operate_type IN (" + GenQuestionMarks(len(operateTypes)) + ")"
|
||||
sqlParams = append(sqlParams, operateTypes)
|
||||
}
|
||||
if len(skuIDs) > 0 {
|
||||
sql += " AND b.thing_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
if len(storeIDs) > 0 {
|
||||
sql += " AND b.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
if keyword != "" {
|
||||
sql += " AND ("
|
||||
var apiList []string
|
||||
for k, v := range model.ApiFunctionName {
|
||||
if strings.Contains(v, keyword) {
|
||||
apiList = append(apiList, k)
|
||||
}
|
||||
}
|
||||
if len(apiList) > 0 {
|
||||
sql += "a.api_function IN (" + GenQuestionMarks(len(apiList)) + ") OR"
|
||||
sqlParams = append(sqlParams, apiList)
|
||||
}
|
||||
sql += " a.err_msg LIKE ? OR b.thing_id LIKE ? OR b.store_id LIKE ? OR c.name LIKE ? OR a.user_id LIKE ?)"
|
||||
sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
|
||||
}
|
||||
sql += `
|
||||
ORDER BY a.created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`
|
||||
sqlParams = append(sqlParams, pageSize, offset)
|
||||
txDB, _ := Begin(db)
|
||||
defer Commit(db, txDB)
|
||||
if err = GetRowsTx(txDB, &operateEventExt, sql, sqlParams...); err == nil {
|
||||
totalCount = GetLastTotalRowCountTx(txDB)
|
||||
}
|
||||
var (
|
||||
accessUUidList []string
|
||||
details []*model.OperateEventDetail
|
||||
detailMap = make(map[string][]*model.OperateEventDetail)
|
||||
)
|
||||
for _, v := range operateEventExt {
|
||||
accessUUidList = append(accessUUidList, v.AccessUUID)
|
||||
}
|
||||
if len(accessUUidList) == 0 {
|
||||
return operateEventExt, totalCount, err
|
||||
}
|
||||
sql2 := `
|
||||
SELECT *
|
||||
FROM operate_event_detail
|
||||
WHERE access_uuid IN (` + GenQuestionMarks(len(accessUUidList)) + `)
|
||||
`
|
||||
sqlParams2 := []interface{}{accessUUidList}
|
||||
err = GetRows(db, &details, sql2, sqlParams2...)
|
||||
for _, v := range details {
|
||||
detailMap[v.AccessUUID] = append(detailMap[v.AccessUUID], v)
|
||||
}
|
||||
for _, v := range operateEventExt {
|
||||
if detailMap[v.AccessUUID] != nil {
|
||||
v.Detail = detailMap[v.AccessUUID]
|
||||
}
|
||||
}
|
||||
return operateEventExt, totalCount, err
|
||||
}
|
||||
|
||||
type GetMessageGroupsResult struct {
|
||||
model.MessageGroup
|
||||
Avatar string `json:"avatar"`
|
||||
LastMessageType int `json:"lastMessageType"`
|
||||
LastContent string `json:"lastContent"`
|
||||
LastTime time.Time `json:"lastTime"`
|
||||
LastUserName string `json:"lastUserName"`
|
||||
UserName string `json:"userName"`
|
||||
UnReadMessageCount int `json:"unReadMessageCount"`
|
||||
MessageGroupMembers []*GetMessageGroupsMemberResult `json:"messageGroupMembers"`
|
||||
}
|
||||
|
||||
type GetMessageGroupsMemberResult struct {
|
||||
model.User
|
||||
model.MessageGroupMember
|
||||
}
|
||||
|
||||
func GetMessageGroups(db *DaoDB, userID string, groupID, groupType int, isMember bool, userID2 string) (messageGroupsResult []*GetMessageGroupsResult, err error) {
|
||||
sql := `
|
||||
SELECT a.*, b.name user_name, b.avatar
|
||||
FROM message_group a
|
||||
LEFT JOIN user b ON b.user_id = a.user_id
|
||||
WHERE a.deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{utils.DefaultTimeValue}
|
||||
if userID != "" {
|
||||
sql += " AND a.user_id = ?"
|
||||
sqlParams = append(sqlParams, userID)
|
||||
}
|
||||
if groupType != 0 {
|
||||
sql += " AND a.type = ?"
|
||||
sqlParams = append(sqlParams, groupType)
|
||||
}
|
||||
if groupID != 0 {
|
||||
sql += " AND a.group_id LIKE ?"
|
||||
sqlParams = append(sqlParams, utils.Int2Str(groupID)+"%")
|
||||
}
|
||||
if err = GetRows(db, &messageGroupsResult, sql, sqlParams); err == nil {
|
||||
if isMember {
|
||||
for _, v := range messageGroupsResult {
|
||||
var messageGroupMembers []*GetMessageGroupsMemberResult
|
||||
sql2 := `
|
||||
SELECT a.*, b.*
|
||||
FROM message_group_member a
|
||||
LEFT JOIN user b ON b.user_id = a.member_user_id
|
||||
WHERE a.group_id = ?
|
||||
AND a.deleted_at = ?
|
||||
`
|
||||
sqlParams2 := []interface{}{v.GroupID, utils.DefaultTimeValue}
|
||||
if userID2 != "" {
|
||||
sql2 += ` AND member_user_id = ?`
|
||||
sqlParams2 = append(sqlParams2, userID2)
|
||||
}
|
||||
if err = GetRows(db, &messageGroupMembers, sql2, sqlParams2); err == nil {
|
||||
v.MessageGroupMembers = messageGroupMembers
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return messageGroupsResult, err
|
||||
}
|
||||
|
||||
func GetMessageGroupMembers(db *DaoDB, groupID, groupType int, memberUserID string) (messageGroupMembers []*model.MessageGroupMember, err error) {
|
||||
sqlParams := []interface{}{}
|
||||
sql := `
|
||||
SELECT a.*
|
||||
FROM message_group_member a
|
||||
`
|
||||
if groupType != 0 {
|
||||
sql += ` JOIN message_group b ON b.group_id = a.group_id AND b.type = ? AND b.deleted_at = ?`
|
||||
sqlParams = append(sqlParams, groupType, utils.DefaultTimeValue)
|
||||
}
|
||||
sql += `
|
||||
WHERE a.deleted_at = ?
|
||||
`
|
||||
sqlParams = append(sqlParams, utils.DefaultTimeValue)
|
||||
if groupID != 0 {
|
||||
sql += " AND a.group_id = ?"
|
||||
sqlParams = append(sqlParams, groupID)
|
||||
}
|
||||
if memberUserID != "" {
|
||||
sql += " AND a.member_user_id = ?"
|
||||
sqlParams = append(sqlParams, memberUserID)
|
||||
}
|
||||
err = GetRows(db, &messageGroupMembers, sql, sqlParams)
|
||||
return messageGroupMembers, err
|
||||
}
|
||||
|
||||
//得到某个用户所在所有群组
|
||||
func GetUserMessageGroups(db *DaoDB, userID string) (messageGroup []*model.MessageGroup, err error) {
|
||||
sql := `
|
||||
SELECT group_id
|
||||
FROM message_group
|
||||
WHERE deleted_at = ? AND user_id = ?
|
||||
UNION
|
||||
SELECT group_id
|
||||
FROM message_group_member
|
||||
WHERE deleted_at = ? AND member_user_id = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue, userID,
|
||||
utils.DefaultTimeValue, userID,
|
||||
}
|
||||
err = GetRows(db, &messageGroup, sql, sqlParams)
|
||||
messageGroup = append(messageGroup, &model.MessageGroup{
|
||||
GroupID: model.SysGroupID,
|
||||
})
|
||||
return messageGroup, err
|
||||
}
|
||||
|
||||
func GetMessageGroupRead(db *DaoDB, userID string, groupID int) (messageGroupReads []*model.MessageGroupRead, err error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM message_group_read a
|
||||
WHERE 1 = 1
|
||||
`
|
||||
sqlParams := []interface{}{}
|
||||
if userID != "" {
|
||||
sql += ` AND a.user_id = ?`
|
||||
sqlParams = append(sqlParams, userID)
|
||||
}
|
||||
if groupID != 0 {
|
||||
sql += ` AND a.group_id = ?`
|
||||
sqlParams = append(sqlParams, groupID)
|
||||
}
|
||||
err = GetRows(db, &messageGroupReads, sql, sqlParams...)
|
||||
return messageGroupReads, err
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package dao
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -63,14 +63,3 @@ func GetPlaceByName(db *DaoDB, name string, level int, parentCode int) (place *m
|
||||
}
|
||||
return place, err
|
||||
}
|
||||
|
||||
func GetPlaceByJdCode(db *DaoDB, jdCode int) (place *model.Place, err error) {
|
||||
if db == nil {
|
||||
db = GetDB()
|
||||
}
|
||||
place = &model.Place{
|
||||
JdCode: jdCode,
|
||||
}
|
||||
err = db.Db.Read(place, "JdCode")
|
||||
return place, err
|
||||
}
|
||||
19
business/dao/print_activation.go
Normal file
19
business/dao/print_activation.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func CheckHeard(printNo string) (bool, error) {
|
||||
var data *model.PrintActivation
|
||||
err := GetRow(GetDB(), &data, `SELECT * FROM print_activation WHERE print_no = ?`, []interface{}{printNo}...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
42
business/dao/print_bind_store.go
Normal file
42
business/dao/print_bind_store.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
// QueryPrintBindStore 查询绑定门店
|
||||
func QueryPrintBindStore(printNo string) ([]*model.PrintBindStore, error) {
|
||||
var data []*model.PrintBindStore
|
||||
if err := GetRows(GetDB(), &data, `SELECT * FROM print_bind_store WHERE print_no = ?`, []interface{}{printNo}...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// BindStoreList 绑定门店信息
|
||||
func BindStoreList(req *model.AddPrinterParam, userId string) error {
|
||||
param := &model.PrintBindStore{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
StoreID: req.StoreId,
|
||||
StoreName: req.Name,
|
||||
StoreVendor: 9, // 绑定平台,全平台
|
||||
PrintNo: req.PrintNo,
|
||||
StoreStatus: 1, // 门店开启
|
||||
BindStatus: 1, // 绑定状态
|
||||
}
|
||||
if userId != "" {
|
||||
param.UserId = userId
|
||||
} else {
|
||||
param.UserId = "system"
|
||||
}
|
||||
return CreateEntity(GetDB(), param)
|
||||
}
|
||||
|
||||
// DeleteStoreList 删除绑定门店
|
||||
func DeleteStoreList(printNo string, storeId string) error {
|
||||
sql := ` DELETE FROM print_bind_store WHERE print_no = ? AND store_id = ? `
|
||||
_, err := ExecuteSQL(GetDB(), sql, []interface{}{printNo, storeId}...)
|
||||
return err
|
||||
}
|
||||
539
business/dao/print_temp_utils.go
Normal file
539
business/dao/print_temp_utils.go
Normal file
@@ -0,0 +1,539 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-print/globals"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var SystemTempObj map[string]*model.SystemTemp
|
||||
|
||||
func Init() {
|
||||
SystemTempObj = make(map[string]*model.SystemTemp, 0)
|
||||
sysTempList, err := QuerySystemTemp()
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debug("query system temp err :", err)
|
||||
return
|
||||
}
|
||||
SystemTempObj[sysTempList.TempSize] = sysTempList
|
||||
|
||||
//now := time.Now()
|
||||
//param := &model.SystemTemp{
|
||||
// CreatedAt: &now,
|
||||
// UpdatedAt: &now,
|
||||
// LastOperator: "system",
|
||||
// DeletedAt: &utils.DefaultTimeValue,
|
||||
// TempName: "",
|
||||
// TempRank: model.SystemTempKey,
|
||||
// Temp: "",
|
||||
// UserId: "system_user",
|
||||
// TempType: model.TempTypeMerchant,
|
||||
// TempSize: model.SystemTempSizeBig,
|
||||
// PrintSn: "system",
|
||||
// IsUse: 1,
|
||||
//}
|
||||
|
||||
// 初始化大字体模板
|
||||
//if _, v := temp[model.SystemTempSizeBig]; !v {
|
||||
// param.TempName = "system" + model.SystemTempSizeBig
|
||||
// param.Temp = model.SystemTempValue
|
||||
// if err := AddTemp(param); err != nil {
|
||||
// globals.SugarLogger.Debug("init system temp err :", err)
|
||||
// }
|
||||
// SystemTempObj[model.SystemTempSizeBig] = param
|
||||
//}
|
||||
|
||||
// 初始化中字体模板
|
||||
//if _, v := temp[model.SystemTempSizeMedium]; !v {
|
||||
// param.TempName = "system" + model.SystemTempSizeMedium
|
||||
// medium := strings.Replace(model.SystemTempValue, "<b>", "<hb>", -1)
|
||||
// medium2 := strings.Replace(medium, "</b>", "</hb>", -1)
|
||||
// param.Temp = medium2
|
||||
// param.TempSize = model.SystemTempSizeMedium
|
||||
// param.IsUse = 2
|
||||
// if err := AddTemp(param); err != nil {
|
||||
// globals.SugarLogger.Debug("init system temp err :", err)
|
||||
// }
|
||||
// SystemTempObj[model.SystemTempSizeMedium] = param
|
||||
//}
|
||||
|
||||
// 初始化小字体模板
|
||||
//if _, v := temp[model.SystemTempSizeSmall]; !v {
|
||||
// param.TempName = "system" + model.SystemTempSizeSmall
|
||||
// medium := strings.Replace(model.SystemTempValue, "<b>", " ", -1)
|
||||
// medium2 := strings.Replace(medium, "</b>", " ", -1)
|
||||
// param.Temp = medium2
|
||||
// param.TempSize = model.SystemTempSizeSmall
|
||||
// param.IsUse = 2
|
||||
// if err := AddTemp(param); err != nil {
|
||||
// globals.SugarLogger.Debug("init system temp err :", err)
|
||||
// }
|
||||
// SystemTempObj[model.SystemTempSizeSmall] = param
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
// MakePrintMsgOnTemp 将打印数据渲染到模板当中
|
||||
func MakePrintMsgOnTemp(param map[string]string, userId string) (string, error) {
|
||||
// 查询用户默认模板,不存在则使用系统默认模板
|
||||
userTemp := &model.SystemTemp{}
|
||||
userTemp, isHave, err := SelectUserDefaultTemp(userId, model.TempTypeMerchantUser)
|
||||
if err != nil || !isHave {
|
||||
userTemp, err = QuerySystemTemp()
|
||||
}
|
||||
if userTemp == nil || !isHave || err != nil {
|
||||
if userTemp.TempType != "" {
|
||||
userTemp = SystemTempObj[userTemp.TempSize]
|
||||
} else {
|
||||
userTemp = SystemTempObj[model.SystemTempSizeBig]
|
||||
}
|
||||
}
|
||||
// 需要打印数据
|
||||
printMsg := ""
|
||||
printValue := make([]interface{}, 0, 0)
|
||||
userTempMap := make(map[string]string, 0)
|
||||
if err := json.Unmarshal([]byte(userTemp.Temp), &userTempMap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, v := range strings.Split(userTemp.TempRank, ",") {
|
||||
switch v {
|
||||
case "skuName", "skuNumber", "skuPrice", "skuAllPrice", "allSkuTypeCount", "allSkuCount", "skuUpc", "userPayMoney":
|
||||
continue
|
||||
case "goodsListDetail":
|
||||
printMsg += userTempMap[v]
|
||||
skuList := make([]*model.SkuListPrintOrder, 0, 0)
|
||||
if err := json.Unmarshal([]byte(param["skuList"]), &skuList); err != nil {
|
||||
return "", err
|
||||
}
|
||||
for i := 0; i < len(skuList); i++ {
|
||||
printMsg += userTempMap["skuName"]
|
||||
printMsg += userTempMap["skuNumber"]
|
||||
printMsg += userTempMap["skuPrice"]
|
||||
printMsg += userTempMap["skuAllPrice"]
|
||||
printValue = append(printValue, skuList[i].SkuName, skuList[i].SkuCount, skuList[i].SalePrice, skuList[i].TotalCountPrice)
|
||||
if skuList[i].Upc != "" {
|
||||
printMsg += userTempMap["skuUpc"]
|
||||
printValue = append(printValue, skuList[i].Upc)
|
||||
}
|
||||
|
||||
}
|
||||
printMsg += userTempMap["allSkuTypeCount"]
|
||||
printValue = append(printValue, param["allSkuTypeCount"])
|
||||
printMsg += userTempMap["allSkuCount"]
|
||||
printValue = append(printValue, param["allSkuCount"])
|
||||
printMsg += userTempMap["userPayMoney"]
|
||||
printValue = append(printValue, param["userPayMoney"])
|
||||
case "businessType":
|
||||
if param[v] == "2" { // 是预订单
|
||||
printMsg += userTempMap[v]
|
||||
printValue = append(printValue, param[v])
|
||||
}
|
||||
case "divider":
|
||||
printMsg += userTempMap[v]
|
||||
case "title":
|
||||
printMsg += userTempMap[v]
|
||||
case "qrcOrder": // 老版打印机展示不要
|
||||
//printMsg += userTempMap[v]
|
||||
//printValue = append(printValue, param[v])
|
||||
printMsg += `<b>%s #%s</b>`
|
||||
printValue = append(printValue, param["vendorName"], param["vendorOrderNo"])
|
||||
default:
|
||||
printMsg += userTempMap[v]
|
||||
printValue = append(printValue, param[v])
|
||||
}
|
||||
|
||||
}
|
||||
return strings.Replace(fmt.Sprintf(strings.Replace(printMsg, "\n", "", -1), printValue...), "\\n", "\r\n", -1), nil
|
||||
//}
|
||||
}
|
||||
|
||||
// MakePrintMsgOnTempVoice 制作平台语音
|
||||
func MakePrintMsgOnTempVoice(param map[string]string, setting *model.PrintSettingObj, userId string) (string, error) {
|
||||
// 打订单
|
||||
if param[model.OrderStatusPrint] != "" {
|
||||
// 订单提示设置
|
||||
printMsg, err := PrinterOrderVoice(param, setting, userId)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debug("err Unmarshal userTemp.printMsg", err)
|
||||
return "", err
|
||||
}
|
||||
return printMsg, nil
|
||||
}
|
||||
// 打运单
|
||||
if param[model.WayBillStatusPrint] != "" {
|
||||
switch param[model.WayBillStatusPrint] {
|
||||
case utils.Int2Str(model.WaybillStatusCourierAssigned): // 分配骑手
|
||||
return PrintWayBillOrderStatus(param, setting), nil
|
||||
case utils.Int2Str(model.WaybillStatusDeliverReminder): // 催单
|
||||
printVoiceMsg := ``
|
||||
printVoiceValue := make([]interface{}, 0, 0)
|
||||
//printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.ReminderOrderVoice)
|
||||
return strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1), nil
|
||||
case utils.Int2Str(model.WaybillStatusDelivered): // 送达
|
||||
printVoiceMsg := ``
|
||||
printVoiceValue := make([]interface{}, 0, 0)
|
||||
//printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.FinialsOrderVoice)
|
||||
return strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1), nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 门店状态
|
||||
if param[model.StoreStatusPrint] != "" {
|
||||
return PrintStoreStatus(param, setting), nil
|
||||
}
|
||||
|
||||
// 进店咨询
|
||||
if param[model.EnterTheStorePrint] != "" && setting.VoiceSetting.ConsultingPrint == model.SettingOpen {
|
||||
return `<sound>19</sound>`, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// PrinterOrderVoice 打印机订单提示设置
|
||||
func PrinterOrderVoice(param map[string]string, setting *model.PrintSettingObj, userId string) (string, error) {
|
||||
var (
|
||||
printVoiceMsg string //语音信息
|
||||
printVoiceValue = make([]interface{}, 0, 0)
|
||||
textMsg string // 文本信息
|
||||
err error
|
||||
)
|
||||
|
||||
// 订单状态
|
||||
switch param[model.OrderStatusPrint] {
|
||||
// 新订单(待接单)
|
||||
case utils.Int2Str(model.OrderStatusNew): // utils.Int2Str(model.OrderStatusFinishedPickup), utils.Int2Str(model.OrderStatusAccepted)
|
||||
//if param[model.OrderStatusPrint] != utils.Int2Str(model.OrderStatusNew) && param[model.VendorIDPrint] == utils.Int64ToStr(model.VendorIDMTWM) {
|
||||
// return "", err
|
||||
//}
|
||||
//if param[model.OrderStatusPrint] == utils.Int2Str(model.OrderStatusFinishedPickup) && param[model.VendorIDPrint] == utils.Int64ToStr(model.VendorIDEBAI) {
|
||||
// return "", err
|
||||
//}
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
}
|
||||
// 订单设置
|
||||
if setting.PrintSetting.WaitOrderPrint == model.SettingOpen { // 打印订单
|
||||
textMsg, err = MakePrintMsgOnTemp(param, userId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if setting.VoiceSetting.WaitOrderVoice == model.SettingOpen { // 订单通知
|
||||
printVoiceMsg += `<sound>%d</sound>` // 你来新订单了
|
||||
printVoiceValue = append(printVoiceValue, model.NewOrderVoice)
|
||||
}
|
||||
// 申请取消
|
||||
case utils.Int2Str(model.ApplyOrderCancel):
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
}
|
||||
// 订单设置
|
||||
if setting.PrintSetting.ApplyUserCancelOrder == model.SettingOpen { // 申请取消打印
|
||||
rejection := ``
|
||||
rejectionValue := make([]interface{}, 0, 0)
|
||||
rejection += `<center><b>客户申请取消订单:</b></center><br>`
|
||||
rejection += `<center><b>订单号: %s</b></center><br>`
|
||||
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
|
||||
rejection += `<center><b>取消时间: %s</b></center><br>`
|
||||
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], utils.Time2DateStr(time.Now()))
|
||||
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
|
||||
}
|
||||
if setting.VoiceSetting.ApplyUserOrderCancelVoice == model.SettingOpen { // 申请取消语音
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.ApplyCancelVoice)
|
||||
//printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
|
||||
}
|
||||
// 申请退货
|
||||
case utils.Int2Str(model.ApplyOrderRefundGoods):
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
}
|
||||
rejection := ``
|
||||
rejectionValue := make([]interface{}, 0, 0)
|
||||
rejection += `<center><b>客户申请退货:</b></center><br>`
|
||||
rejection += `<center><b>订单号: %s</b></center><br>`
|
||||
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
|
||||
rejection += `<center><b>原因: %s</b></center><br>`
|
||||
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.RejectionReasonPrint])
|
||||
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
|
||||
|
||||
if setting.VoiceSetting.ApplyRefundGoodsVoice == model.SettingOpen { // 申请退货语音
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.ApplyReturnGoodsVoice)
|
||||
// printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
|
||||
}
|
||||
// 申请退款
|
||||
case utils.Int2Str(model.ApplyOrderRefund):
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
}
|
||||
// 订单设置
|
||||
if setting.PrintSetting.ApplyUserRefund == model.SettingOpen { // 取消退款订单
|
||||
textMsg, err = MakePrintMsgOnTemp(param, userId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if setting.VoiceSetting.ApplyRefundOrderVoice == model.SettingOpen {
|
||||
//printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.ApplyRefundVoice)
|
||||
}
|
||||
// 取消打印
|
||||
|
||||
case utils.Int2Str(model.OrderStatusRejection): // 拒收
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
}
|
||||
//if setting.VoiceSetting.CustomerRejectionVoice == model.SettingOpen && setting.SystemVoice == model.SettingOpen {
|
||||
// // 暂无语音打印
|
||||
//}
|
||||
// 拒收暂无语音设置,使用文本提示
|
||||
if setting.PrintSetting.CustomerRejectionPrint == model.SettingOpen { // 客户拒收打印
|
||||
rejection := ``
|
||||
rejectionValue := make([]interface{}, 0, 0)
|
||||
rejection += `<center><b>客户拒收信息:</b></center><br>`
|
||||
rejection += `<center><b>订单号: %s</b></center><br>`
|
||||
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
|
||||
rejection += `<center><b>拒收原因: %s</b></center><br>`
|
||||
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.RejectionReasonPrint])
|
||||
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
|
||||
}
|
||||
|
||||
case utils.Int2Str(model.OrderStatusCustomerService): // 客服退款
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
}
|
||||
if setting.VoiceSetting.CusterRefundVoice == model.SettingOpen {
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.BusinessResponsibilityVoice)
|
||||
}
|
||||
if setting.PrintSetting.CusterRefundPrint == model.SettingOpen {
|
||||
rejection := ``
|
||||
rejectionValue := make([]interface{}, 0, 0)
|
||||
rejection += `<center><b>客服退款详情:</b></center><br>`
|
||||
rejection += `<center><b>订单号: %s</b></center><br>`
|
||||
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
|
||||
rejection += `<center><b>退款原因: %s</b></center><br>`
|
||||
rejection += `<center><b>退款时间: %s</b></center><br>`
|
||||
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.CustcareRefundReasonPrint], utils.Time2DateStr(time.Now()))
|
||||
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
|
||||
}
|
||||
case utils.Int2Str(model.OrderStatusCanceled), utils.Int2Str(model.CancelOrderSuccess): // 取消订单成功
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
if setting.VoiceSetting.RefundGoodsVoice == model.SettingOpen {
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.CancelOrderVoice)
|
||||
}
|
||||
}
|
||||
if setting.PrintSetting.CusterRefundPrint == model.SettingOpen {
|
||||
rejection := ``
|
||||
rejectionValue := make([]interface{}, 0, 0)
|
||||
rejection += `<center><b>订单取消成功:</b></center><br>`
|
||||
rejection += `<center><b>订单号: %s</b></center><br>`
|
||||
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
|
||||
rejection += `<center><b>取消原因: %s</b></center><br>`
|
||||
rejection += `<center><b>取消成功时间: %s</b></center><br>`
|
||||
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.CustcareRefundReasonPrint], utils.Time2DateStr(time.Now()))
|
||||
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
|
||||
}
|
||||
case utils.Int2Str(model.BusinessCancelOrder): // 商家取消打印
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
}
|
||||
if setting.PrintSetting.BusinessOrderCancel == model.SettingOpen {
|
||||
rejection := ``
|
||||
rejectionValue := make([]interface{}, 0, 0)
|
||||
rejection += `<center><b>商家侧取消订单:</b></center><br>`
|
||||
rejection += `<center><b>订单号: %s</b></center><br>`
|
||||
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
|
||||
rejection += `<center><b>取消原因: %s</b></center><br>`
|
||||
rejection += `<center><b>取消成功时间: %s</b></center><br>`
|
||||
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.CustcareRefundReasonPrint], utils.Time2DateStr(time.Now()))
|
||||
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
|
||||
}
|
||||
case utils.Int2Str(model.OrderRefundMoneySuccess): // 订单退款成功打印
|
||||
// 称谓设置/平台语音设置
|
||||
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
|
||||
// 老板
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
|
||||
}
|
||||
if setting.PrintSetting.OrderCancelSuccess == model.SettingOpen {
|
||||
rejection := ``
|
||||
rejectionValue := make([]interface{}, 0, 0)
|
||||
rejection += `<center><b>退款成功:</b></center><br>`
|
||||
rejection += `<center><b>订单号: %s</b></center><br>`
|
||||
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
|
||||
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint])
|
||||
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
|
||||
}
|
||||
}
|
||||
|
||||
voice := strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1)
|
||||
return voice + textMsg, nil
|
||||
}
|
||||
|
||||
// PrintWayBillOrderStatus 打印运单类通知消息
|
||||
func PrintWayBillOrderStatus(param map[string]string, setting *model.PrintSettingObj) string {
|
||||
var (
|
||||
printVoiceMsg string //语音信息
|
||||
printVoiceValue = make([]interface{}, 0, 0)
|
||||
textMsg string // 文本信息
|
||||
textMsgValue = make([]interface{}, 0, 0) // 文本信息
|
||||
)
|
||||
|
||||
switch param[model.WayBillStatusPrint] {
|
||||
case utils.Int2Str(model.WaybillStatusAccepted), utils.Int2Str(model.WaybillStatusCourierAssigned): // 分配骑手
|
||||
if setting.PrintSetting.RiderTakeOrder == model.SettingOpen { // 打印订单
|
||||
textMsg += `<center><b>接单骑手信息:</b></center><br>`
|
||||
textMsg += `<center><b>骑手姓名: %s</b></center><br>`
|
||||
textMsg += `<center><b>骑手电话: %s</b></center><br>`
|
||||
textMsg += `<center><b>接单时间: %s</b></center><br>`
|
||||
textMsg += `<center><b>订单来源: %s</b></center><br>`
|
||||
textMsg += `<center><b>单号: #%s</b></center><br>`
|
||||
textMsgValue = append(textMsgValue, param[model.RiderNamePrint], param[model.RiderPhonePrint], utils.Time2DateStr(time.Now()), param[model.VendorNamePrint], param[model.VendorOrderNoPrint])
|
||||
}
|
||||
}
|
||||
if setting.VoiceSetting.RiderTakeOrderVoice == model.SettingOpen { // 骑手接单语音通知
|
||||
printVoiceMsg += `<sound>%d</sound><sound>%d</sound>` // 骑手已经接单了
|
||||
printVoiceValue = append(printVoiceValue, model.RiderGetOrderVoice)
|
||||
}
|
||||
|
||||
msg := strings.Replace(fmt.Sprintf(strings.Replace(textMsg, "\n", "", -1), textMsgValue...), "\\n", "\r\n", -1)
|
||||
voice := strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1)
|
||||
return voice + msg
|
||||
}
|
||||
|
||||
// PrintStoreStatus 打印门店状态
|
||||
func PrintStoreStatus(param map[string]string, setting *model.PrintSettingObj) string {
|
||||
var (
|
||||
printVoiceMsg string //语音信息
|
||||
printVoiceValue = make([]interface{}, 0, 0)
|
||||
textMsg string // 文本信息
|
||||
textMsgValue = make([]interface{}, 0, 0)
|
||||
)
|
||||
|
||||
switch utils.Str2Int(param[model.StoreStatusPrint]) {
|
||||
case -9: // 丢失授权
|
||||
var voice string
|
||||
if setting.VoiceSetting.LoseAuthorization == model.SettingOpen {
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.LoseTokenVoice)
|
||||
voice = strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1)
|
||||
}
|
||||
|
||||
textMsg += `<left><b>门店丢失授权通知</b></left><br>`
|
||||
textMsg += `<left><b>门店:%s</b></left><br>`
|
||||
textMsg += `<left><b>平台:%s</b></left><br>`
|
||||
textMsg += `<left><b>下线时间:%s</b></left><br>`
|
||||
textMsg += `<left><b>授权丢失,将无法继续打压订单!!!!</b></left><br>`
|
||||
textMsgValue = append(textMsgValue, param[model.StoreNamePrint], param[model.VendorNamePrint], utils.Time2DateStr(time.Now()))
|
||||
msg := strings.Replace(fmt.Sprintf(strings.Replace(textMsg, "\n", "", -1), textMsgValue...), "\\n", "\r\n", -1)
|
||||
return voice + msg
|
||||
default:
|
||||
// 离线打印文本开启
|
||||
textMsg += `<center><b>门店下线通知</b></center><br>`
|
||||
textMsg += `<center><b>门店:%s</b></center><br>`
|
||||
textMsg += `<center><b>平台:%s</b></center><br>`
|
||||
textMsg += `<center><b>下线时间:%s</b></center><br>`
|
||||
textMsgValue = append(textMsgValue, param[model.StoreNamePrint], param[model.VendorNamePrint], utils.Time2DateStr(time.Now()))
|
||||
// 离线打印语音开启
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.StoreOfflineVoice)
|
||||
voice := strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1)
|
||||
msg := strings.Replace(fmt.Sprintf(strings.Replace(textMsg, "\n", "", -1), textMsgValue...), "\\n", "\r\n", -1)
|
||||
|
||||
return voice + msg
|
||||
}
|
||||
}
|
||||
|
||||
// SyntheticSpeech 合成语音 (美团xxx号订单)
|
||||
func SyntheticSpeech(printVoiceMsg string, printVoiceValue []interface{}, param map[string]string) (string, []interface{}) {
|
||||
printVoiceMsg += `<sound>%d</sound>` // 美团
|
||||
switch param[model.VendorIDPrint] {
|
||||
case utils.Int2Str(model.VendorIDJD): // 京东
|
||||
printVoiceValue = append(printVoiceValue, model.JdVoice)
|
||||
case utils.Int2Str(model.VendorIDMTWM): // 美团
|
||||
printVoiceValue = append(printVoiceValue, model.MtVoice)
|
||||
case utils.Int2Str(model.VendorIDELM): // 饿了么
|
||||
printVoiceValue = append(printVoiceValue, model.ElmVoice)
|
||||
case utils.Int2Str(model.VendorIDEBAI): // 饿百
|
||||
printVoiceValue = append(printVoiceValue, model.ElmVoice)
|
||||
case utils.Int2Str(model.VendorIDJDShop): // 京东商城
|
||||
printVoiceValue = append(printVoiceValue, model.JdToHose)
|
||||
case utils.Int2Str(model.VendorIDTT): // 抖音
|
||||
// 暂无
|
||||
}
|
||||
if param[model.VendorOrderNoPrint] != "" {
|
||||
switch len(param[model.VendorOrderNoPrint]) {
|
||||
case 1:
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint]])
|
||||
case 2:
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][:1]+"0"])
|
||||
if param[model.VendorOrderNoPrint][1:] != "0" {
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][1:]])
|
||||
}
|
||||
case 3:
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][0:1]+"00"])
|
||||
if param[model.VendorOrderNoPrint][1:2] == "0" && param[model.VendorOrderNoPrint][2:] == "0" {
|
||||
|
||||
} else if param[model.VendorOrderNoPrint][1:2] == "0" && param[model.VendorOrderNoPrint][2:] != "0" {
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][1:2]])
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][2:]])
|
||||
} else if param[model.VendorOrderNoPrint][1:2] != "0" && param[model.VendorOrderNoPrint][2:] == "0" {
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][1:2]+"0"])
|
||||
} else if param[model.VendorOrderNoPrint][1:2] != "0" && param[model.VendorOrderNoPrint][2:] != "0" {
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][1:2]+"0"])
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][2:]])
|
||||
}
|
||||
}
|
||||
}
|
||||
printVoiceMsg += `<sound>%d</sound>`
|
||||
printVoiceValue = append(printVoiceValue, model.OrderNoVoice)
|
||||
return printVoiceMsg, printVoiceValue
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func (c *OrderManager) OnNewFakeJdOrder(vendorOrderID string) (err error) {
|
||||
utils.CallFuncAsync(func() {
|
||||
orderInfo, err := api.FakeJdAPI.FakeQuerySingleOrderRaw(vendorOrderID)
|
||||
if err == nil {
|
||||
order := jd.Map2Order(orderInfo)
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
err = c.notifyNewFakeJdOrder(order)
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("OnNewFakeJdOrder failed with err:%v", err)
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) notifyNewFakeJdOrder(order *model.GoodsOrder) (err error) {
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, model.VendorIDJD)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
realStoreID := storeDetail.ID
|
||||
if storeDetail.LinkStoreID != 0 {
|
||||
realStoreID = storeDetail.LinkStoreID
|
||||
}
|
||||
notifyWxNewFakeJdOrder(order, realStoreID)
|
||||
netprinter.PrintOrderByOrder4Store(jxcontext.AdminCtx, order, realStoreID)
|
||||
return err
|
||||
}
|
||||
|
||||
func notifyWxNewFakeJdOrder(order *model.GoodsOrder, storeID int) (err error) {
|
||||
globals.SugarLogger.Debugf("notifyWxNewFakeJdOrder orderID:%s", order.VendorOrderID)
|
||||
|
||||
sb := new(strings.Builder)
|
||||
sb.WriteString("老板,你有新订单了\n")
|
||||
sb.WriteString(fmt.Sprintf("订单号:%s\n", order.VendorOrderID))
|
||||
sb.WriteString("送达时间:")
|
||||
if order.BusinessType == model.BusinessTypeDingshida {
|
||||
sb.WriteString(utils.Time2Str(order.ExpectedDeliveredTime))
|
||||
} else {
|
||||
sb.WriteString("立即达")
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(fmt.Sprintf("买家:%s\n", order.ConsigneeName))
|
||||
sb.WriteString(fmt.Sprintf("电话:%s\n", order.ConsigneeMobile))
|
||||
sb.WriteString(fmt.Sprintf("收货地址:%s\n", order.ConsigneeAddress))
|
||||
sb.WriteString("商品详情:\n")
|
||||
for _, sku := range order.Skus {
|
||||
sb.WriteString(fmt.Sprintf("\t%s*%d\n", sku.SkuName, sku.Count))
|
||||
}
|
||||
title := fmt.Sprintf("你有到家菜市新订单%d", order.OrderSeq)
|
||||
content := sb.String()
|
||||
// globals.SugarLogger.Debugf("notifyWxNewFakeJdOrder, orderID:%s, content:%s", order.VendorOrderID, content)
|
||||
_, err = weixinmsg.SendStoreMessage(jxcontext.AdminCtx, title, content, []int{storeID}, true, true)
|
||||
return err
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestOnNewFakeJdOrder(t *testing.T) {
|
||||
err := FixedOrderManager.OnNewFakeJdOrder("2002984074001021")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
TotalRate = 200 // 总费率(千分之200)= 第三方平台费+京西品牌费+京西服务费,现阶段都是合计200‰
|
||||
MaxFreightMoneyFromJxByShop = 7 // 商家自送实际转美团/达达后由商家承担的运费金额上限
|
||||
)
|
||||
|
||||
// 处理正向订单结账信息
|
||||
func (c *OrderManager) SaveOrderFinancialInfo(order *model.OrderFinancial, operation string) (err error) {
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if operation == partner.UpdatedPeration {
|
||||
// db := orm.NewOrm()
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_financial WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_sku_financial WHERE vendor_order_id = ? AND vendor_id = ? AND is_afs_order = 0", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_sku_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_discount_financial WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_discount_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, activity := range order.Discounts {
|
||||
if err = dao.CreateEntity(db, activity); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderDiscountFinancialInfo order.VendorOrderID:%s err: order is err", order.VendorOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
order.ShopMoneyByCal = order.SalePriceMoney - order.TotalDiscountMoney - order.PointsDeductionMoney + order.PmFreightDiscountMoney - order.DistanceFreightMoney - order.FreightTipsMoney - order.DonationMoney + order.SelfDeliveryDiscountMoney + order.PmSubsidyMoney + order.SkuBoxMoney + order.BoxMoney - order.PmMoney
|
||||
order.JxPmMoney = utils.Float64TwoInt64(float64(order.ShopMoney+order.PmMoney)*TotalRate/1000) - order.PmMoney // 京西平台费 = 总金额*20%-第三方平台费
|
||||
if order.JxPmMoney < 0 { // 如果算出京西平台费为负数,则置0
|
||||
order.JxPmMoney = 0
|
||||
}
|
||||
|
||||
order.JxShopMoney = order.ShopMoney - order.JxPmMoney + order.JxSubsidyMoney - order.JxFreightMoneyByShop
|
||||
// 订单结算金额拆分计算,拆分到单条sku
|
||||
// 先获取订单主体优惠金额
|
||||
platOrderGoodsDiscountMoney := order.PmSubsidyMoney - order.PmSkuSubsidyMoney + order.SelfDeliveryDiscountMoney
|
||||
// 结算平台扣除项汇总---平台佣金,商家设置运费减免,远距离费,小费,公益捐款、、、、
|
||||
deductionsByPm := order.FreightDiscountMoney + order.DistanceFreightMoney + order.FreightTipsMoney + order.DonationMoney + order.PmMoney
|
||||
// 结算京西扣除项汇总---京西佣金,京西配送运费
|
||||
deductionsByJx := order.JxPmMoney + order.JxFreightMoneyByShop
|
||||
for _, sku := range order.Skus[1:] {
|
||||
// 用户支付菜品金额,用户为这一条sku支付的菜品金额
|
||||
sku.UserMoney = utils.Float64TwoInt64(float64(order.SalePriceMoney-order.DiscountMoney-order.PointsDeductionMoney+order.BoxMoney+order.SkuBoxMoney) * float64(sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney) / float64(order.SalePriceMoney+order.SkuBoxMoney)) // 林峰确认,比如49-2满减,算餐盒费满49元,不算餐盒费不足49元,是可以参加满减活动的,那么餐盒费也应该和商品金额一起进行折算
|
||||
order.Skus[0].UserMoney += sku.UserMoney
|
||||
// 计算平台订单主体补贴拆分到单条sku的金额 + sku.PmSubsidyMoneyForSku
|
||||
sku.PmSubsidyMoney = sku.PmSkuSubsidyMoney + utils.Float64TwoInt64(float64(platOrderGoodsDiscountMoney*sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney)/float64(order.SalePriceMoney+order.SkuBoxMoney))
|
||||
order.Skus[0].PmSubsidyMoney += sku.PmSubsidyMoney
|
||||
// 计算京西满减补贴拆分到单条sku的金额 + sku.JxSubsidyMoneyForSku
|
||||
sku.JxSubsidyMoney = sku.JxSkuSubsidyMoney + utils.Float64TwoInt64(float64(order.JxSubsidyMoney-order.PmSkuSubsidyMoney)*float64(sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney)/float64(order.SalePriceMoney+order.SkuBoxMoney))
|
||||
order.Skus[0].JxSubsidyMoney += sku.JxSubsidyMoney
|
||||
// 计算单条sku需要承担的平台扣费金额
|
||||
sku.PmDeductionsMoney = utils.Float64TwoInt64(float64(deductionsByPm) * (float64(sku.UserMoney + sku.PmSubsidyMoney)) / (float64(order.SalePriceMoney + order.BoxMoney + order.SkuBoxMoney - order.DiscountMoney - order.PointsDeductionMoney + order.PmSubsidyMoney)))
|
||||
order.Skus[0].PmDeductionsMoney += sku.PmDeductionsMoney
|
||||
// 计算单条sku平台应该结算给京西的金额
|
||||
sku.ShopMoneyByCal = sku.UserMoney + sku.PmSubsidyMoney - sku.PmDeductionsMoney
|
||||
order.Skus[0].ShopMoneyByCal += sku.ShopMoneyByCal
|
||||
// j计算单条sku需要承担的京西扣费金额
|
||||
sku.JxDeductionsMoney = utils.Float64TwoInt64(float64(deductionsByJx*sku.ShopMoneyByCal) / float64(order.ShopMoney))
|
||||
order.Skus[0].JxDeductionsMoney += sku.JxDeductionsMoney
|
||||
// 计算单条sku京西应该结算给商家的金额
|
||||
sku.JxShopMoney = sku.ShopMoneyByCal + sku.JxSubsidyMoney - sku.JxDeductionsMoney
|
||||
order.Skus[0].JxShopMoney += sku.JxShopMoney
|
||||
if sku.SkuID >= math.MaxInt32 {
|
||||
sku.SkuID = sku.JxSkuID
|
||||
}
|
||||
if err = dao.CreateEntity(db, sku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(order.Skus) > 0 {
|
||||
sku := order.Skus[0]
|
||||
if sku.SkuID > math.MaxInt32 {
|
||||
sku.SkuID = sku.JxSkuID
|
||||
}
|
||||
sku.UserMoney = order.SalePriceMoney - order.DiscountMoney - sku.UserMoney
|
||||
sku.PmSubsidyMoney = platOrderGoodsDiscountMoney + order.SelfDeliveryDiscountMoney - sku.PmSubsidyMoney
|
||||
sku.JxSubsidyMoney = order.JxSubsidyMoney - sku.JxSubsidyMoney
|
||||
sku.PmDeductionsMoney = deductionsByPm - sku.PmDeductionsMoney
|
||||
sku.ShopMoneyByCal = order.ShopMoney - sku.ShopMoneyByCal
|
||||
sku.JxDeductionsMoney = deductionsByJx - sku.JxDeductionsMoney
|
||||
sku.JxShopMoney = order.JxShopMoney - sku.JxShopMoney
|
||||
if err = dao.CreateEntity(db, sku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err: order have no sku", order.VendorOrderID)
|
||||
}
|
||||
// 加上京西对单条sku的补贴,再存数据库
|
||||
order.JxSubsidyMoney += order.JxSkuSubsidyMoney
|
||||
if err = dao.CreateEntity(db, order); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderFinancialInfo order.VendorOrderID:%s err: order is err", order.VendorOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
// 处理售后订单结账信息
|
||||
func (c *OrderManager) SaveAfsOrderFinancialInfo(afsOrder *model.AfsOrder) (err error) {
|
||||
globals.SugarLogger.Debug(afsOrder.AfsOrderID)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
|
||||
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
|
||||
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
|
||||
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
|
||||
if err = dao.CreateEntity(db, afsOrder); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrder is err", afsOrder.AfsOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额(+该条sku承担的平台结算扣除金额)
|
||||
for _, orderSku := range afsOrder.Skus[1:] {
|
||||
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
|
||||
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
|
||||
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrderSku is err", afsOrder.AfsOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(afsOrder.Skus) > 0 {
|
||||
orderSku := afsOrder.Skus[0]
|
||||
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrderSku is err", afsOrder.AfsOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
// 转自送实际使用美团/达达配送,调用此方法
|
||||
func (c *OrderManager) UpdataOrderFinancialInfo(orderFinancial *model.OrderFinancial, wayBill *model.Waybill) (err error) {
|
||||
// 通过本地数据库去取是否转美团/达达,并计算运费,写在上级调用函数里面传递过来
|
||||
// wayBill, err2 := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
|
||||
// if err = err2; err == nil {
|
||||
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
|
||||
// }
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
orderFinancial.JxFreightMoney = wayBill.DesiredFee
|
||||
if (orderFinancial.JxFreightMoney - orderFinancial.SelfDeliveryDiscountMoney) > MaxFreightMoneyFromJxByShop {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.SelfDeliveryDiscountMoney + MaxFreightMoneyFromJxByShop
|
||||
} else if (orderFinancial.JxFreightMoney - orderFinancial.SelfDeliveryDiscountMoney) < 0 {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.SelfDeliveryDiscountMoney
|
||||
} else {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.JxFreightMoney
|
||||
}
|
||||
orderFinancial.JxShopMoney -= orderFinancial.JxFreightMoneyByShop
|
||||
// orderFinancial.JxFreightMoneyByShop 的改变直接影响到单条sku的京西结算金额的改变
|
||||
jxDecMoney := orderFinancial.JxFreightMoneyByShop
|
||||
for _, sku := range orderFinancial.Skus[1:] {
|
||||
// 重新计算单条sku京西应该结算的金额
|
||||
skuJxDecMoney := utils.Float64TwoInt64(float64(jxDecMoney*sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney) / float64(orderFinancial.SalePriceMoney+orderFinancial.SkuBoxMoney))
|
||||
sku.JxDeductionsMoney += skuJxDecMoney
|
||||
sku.JxShopMoney -= skuJxDecMoney
|
||||
jxDecMoney -= skuJxDecMoney
|
||||
if _, err = dao.UpdateEntity(db, sku); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(orderFinancial.Skus) > 0 {
|
||||
sku := orderFinancial.Skus[0]
|
||||
sku.JxDeductionsMoney += jxDecMoney
|
||||
sku.JxShopMoney -= jxDecMoney
|
||||
if _, err = dao.UpdateEntity(db, sku); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = dao.CreateEntity(db, orderFinancial); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveOrderFinancialInfo err: order is err")
|
||||
return err
|
||||
}
|
||||
dao.Commit(db)
|
||||
// orderFinancial 和 OrderSkuFinancial 数据计算完毕,准备进行更新
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,424 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
func (c *OrderManager) LoadAfsOrder(vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
return c.loadAfsOrder(dao.GetDB(), vendorAfsOrderID, vendorID)
|
||||
}
|
||||
|
||||
func (c *OrderManager) loadAfsOrder(db *dao.DaoDB, vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
AfsOrderID: vendorAfsOrderID,
|
||||
VendorID: vendorID,
|
||||
}
|
||||
if err = dao.GetEntity(db, afsOrder, "AfsOrderID", "VendorID"); err != nil {
|
||||
afsOrder = nil
|
||||
}
|
||||
return afsOrder, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
return c.onAfsOrderNew(afsOrder, orderStatus, true)
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
return c.onAfsOrderNew(afsOrder, orderStatus, false)
|
||||
}
|
||||
|
||||
func (c *OrderManager) onAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus, isAdjust bool) (err error) {
|
||||
db := dao.GetDB()
|
||||
globals.SugarLogger.Debugf("onAfsOrderNew1 orderID:%s", afsOrder.VendorOrderID)
|
||||
c.setAfsOrderID(db, orderStatus)
|
||||
if afsOrder.AfsOrderID == "" {
|
||||
afsOrder.AfsOrderID = orderStatus.VendorOrderID
|
||||
}
|
||||
if afsOrder.VendorStatus == "" {
|
||||
afsOrder.VendorStatus = orderStatus.VendorStatus
|
||||
}
|
||||
if afsOrder.Status == model.OrderStatusUnknown {
|
||||
afsOrder.Status = orderStatus.Status
|
||||
}
|
||||
globals.SugarLogger.Debugf("onAfsOrderNew2 orderID:%s", afsOrder.VendorOrderID)
|
||||
//
|
||||
if order, _ := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
|
||||
if order.ConsigneeMobile2 == "" {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
|
||||
order.ConsigneeMobile = order2.ConsigneeMobile
|
||||
c.UpdateOrderFields(order, []string{"ConsigneeMobile"})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
|
||||
globals.SugarLogger.Debugf("onAfsOrderNew afsOrderID:%s, isDuplicated:%t", afsOrder.AfsOrderID, isDuplicated)
|
||||
if err != nil || isDuplicated {
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
}
|
||||
return err
|
||||
}
|
||||
var existAfsOrder *model.AfsOrder
|
||||
if existAfsOrder, err = c.loadAfsOrder(db, afsOrder.AfsOrderID, afsOrder.VendorID); err != nil {
|
||||
if !dao.IsNoRowsError(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if existAfsOrder != nil {
|
||||
// todo 可能导致状态回绕
|
||||
existAfsOrder.Status = afsOrder.Status
|
||||
existAfsOrder.VendorStatus = afsOrder.VendorStatus
|
||||
if _, err = dao.UpdateEntity(db, existAfsOrder, "Status", "VendorStatus"); err != nil {
|
||||
return err
|
||||
}
|
||||
afsOrder = existAfsOrder
|
||||
} else {
|
||||
// 全退都要先全删除再建
|
||||
if afsOrder.RefundType == model.AfsTypeFullRefund {
|
||||
isAdjust = true
|
||||
}
|
||||
if err = c.SaveAfsOrder(db, afsOrder, isAdjust); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dao.Commit(db)
|
||||
scheduler.CurrentScheduler.OnAfsOrderNew(afsOrder, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) SaveAfsOrder(db *dao.DaoDB, afsOrder *model.AfsOrder, isDeleteFirst bool) (err error) {
|
||||
globals.SugarLogger.Debug(afsOrder.AfsOrderID)
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
if err = c.updateAfsOrderOtherInfo(db, afsOrder); err != nil {
|
||||
return err
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if isDeleteFirst {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.DeleteEntity(db, afsOrder, "VendorOrderID", "VendorID")
|
||||
return err
|
||||
}, "SaveAfsOrder delete AfsOrder, afsOrderID:%s", afsOrder.AfsOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.DeleteEntity(db, &model.OrderSkuFinancial{
|
||||
VendorOrderID: afsOrder.VendorOrderID,
|
||||
VendorID: afsOrder.VendorID,
|
||||
IsAfsOrder: 1,
|
||||
}, "VendorOrderID", "VendorID", "IsAfsOrder")
|
||||
return err
|
||||
}, "SaveAfsOrder delete OrderSkuFinancial, afsOrderID:%s", afsOrder.AfsOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
|
||||
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
|
||||
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
|
||||
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
|
||||
if err = dao.CreateEntity(db, afsOrder); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v", afsOrder.AfsOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额(+该条sku承担的平台结算扣除金额)
|
||||
for _, orderSku := range afsOrder.Skus[1:] {
|
||||
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
|
||||
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
|
||||
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v, orderSku:%s", afsOrder.AfsOrderID, err, utils.Format4Output(orderSku, true))
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(afsOrder.Skus) > 0 {
|
||||
orderSku := afsOrder.Skus[0]
|
||||
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v, orderSku:%s", afsOrder.AfsOrderID, err, utils.Format4Output(orderSku, true))
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderStatusChanged(orderStatus *model.OrderStatus) (err error) {
|
||||
db := dao.GetDB()
|
||||
c.setAfsOrderID(db, orderStatus)
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
isDuplicated, afsOrder, err := c.addAfsOrderStatus(db, orderStatus)
|
||||
if err != nil || isDuplicated {
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
}
|
||||
return err
|
||||
}
|
||||
dao.Commit(db)
|
||||
scheduler.CurrentScheduler.OnAfsOrderStatusChanged(afsOrder, orderStatus, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) addAfsOrderStatus(db *dao.DaoDB, orderStatus *model.OrderStatus) (isDuplicated bool, order *model.AfsOrder, err error) {
|
||||
globals.SugarLogger.Debugf("addAfsOrderStatus refOrderID:%s, orderID:%s", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID)
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
|
||||
if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
|
||||
order = &model.AfsOrder{
|
||||
AfsOrderID: orderStatus.VendorOrderID,
|
||||
VendorID: orderStatus.VendorID,
|
||||
}
|
||||
if err = db.Db.ReadForUpdate(order, "AfsOrderID", "VendorID"); err == nil {
|
||||
if orderStatus.Status > model.OrderStatusUnknown { // todo 要求status不能回绕
|
||||
order.VendorStatus = orderStatus.VendorStatus
|
||||
order.Status = orderStatus.Status
|
||||
updateFields := []string{
|
||||
"VendorStatus",
|
||||
"Status",
|
||||
}
|
||||
if model.IsAfsOrderFinalStatus(orderStatus.Status) {
|
||||
order.AfsFinishedAt = orderStatus.StatusTime
|
||||
updateFields = append(updateFields, "AfsFinishedAt")
|
||||
}
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntity(db, order, updateFields...)
|
||||
return err
|
||||
}, "addAfsOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
|
||||
} else {
|
||||
isDuplicated = true
|
||||
}
|
||||
} else {
|
||||
if dao.IsNoRowsError(err) { // todo 消息错序
|
||||
err = nil
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("addAfsOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return isDuplicated, order, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateAfsOrderSkuOtherInfo(db *dao.DaoDB, order *model.AfsOrder) (err error) {
|
||||
globals.SugarLogger.Debugf("updateAfsOrderSkuOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID)
|
||||
jxStoreID := jxutils.GetSaleStoreIDFromAfsOrder(order)
|
||||
opNumStr := "2"
|
||||
if jxStoreID == 0 {
|
||||
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]订单在京西与平台都找不到京西门店信息orderID:%s, VendorStoreID:%s", opNumStr, order.VendorOrderID, order.VendorStoreID)
|
||||
return nil
|
||||
}
|
||||
orderSkus := order.Skus
|
||||
var vendorSkuIDs []string
|
||||
skuIDMap := make(map[int]int)
|
||||
for _, v := range orderSkus {
|
||||
if v.VendorSkuID != "" {
|
||||
vendorSkuIDs = append(vendorSkuIDs, v.VendorSkuID)
|
||||
}
|
||||
|
||||
if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 {
|
||||
skuIDMap[skuID] = 1
|
||||
}
|
||||
}
|
||||
if len(vendorSkuIDs) > 0 {
|
||||
var vendorStoreID string
|
||||
if order.VendorID == model.VendorIDJDShop {
|
||||
vendorStoreID = model.JdShopMainVendorStoreID
|
||||
} else {
|
||||
vendorStoreID = order.VendorStoreID
|
||||
}
|
||||
l, err := dao.GetStoreSkuPriceAndWeight(db, vendorStoreID, order.VendorID, vendorSkuIDs)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("updateAfsOrderSkuOtherInfo orderID:%s failed with err:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
skumapper := storeSkuPriceAndWeight2Map(l)
|
||||
|
||||
var actStoreSkuMap *jxutils.ActStoreSkuMap
|
||||
if len(skuIDMap) > 0 {
|
||||
if order2, err2 := c.LoadOrder(order.VendorOrderID, order.VendorID); err2 == nil {
|
||||
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order2.OrderCreatedAt, order2.OrderCreatedAt)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("updateAfsOrderSkuOtherInfo can not get sku promotion info for error:%v", err)
|
||||
return err
|
||||
}
|
||||
actStoreSkuMap = jxutils.NewActStoreSkuMap(actStoreSkuList, false)
|
||||
}
|
||||
}
|
||||
for _, v := range orderSkus {
|
||||
v.AfsOrderID = order.AfsOrderID
|
||||
v.VendorID = order.VendorID
|
||||
v.VendorOrderID = order.VendorOrderID
|
||||
v.IsAfsOrder = 1
|
||||
v.VendorStoreID = order.VendorStoreID
|
||||
v.StoreID = order.StoreID
|
||||
v.JxStoreID = jxStoreID
|
||||
|
||||
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
|
||||
if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
|
||||
skuBindInfo := skumapper[v.VendorSkuID]
|
||||
if skuBindInfo == nil {
|
||||
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]%s订单sku找不到门店价格(或商品映射),orderID:%s, StoreID:%d, VendorSkuID:%s, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.VendorSkuID, v)
|
||||
} else {
|
||||
v.JxSkuID = skuBindInfo.SkuID
|
||||
v.ShopPrice = int64(skuBindInfo.Price)
|
||||
}
|
||||
}
|
||||
if actStoreSkuMap != nil {
|
||||
if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 && v.StoreSubName != "" {
|
||||
if actStoreSku := actStoreSkuMap.GetActStoreSku(jxStoreID, skuID, order.VendorID); actStoreSku != nil {
|
||||
v.StoreSubID = actStoreSku.ActID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateAfsOrderOtherInfo(db *dao.DaoDB, afsOrder *model.AfsOrder) (err error) {
|
||||
globals.SugarLogger.Debugf("updateAfsOrderOtherInfo orderID:%s, VendorStoreID:%s", afsOrder.VendorOrderID, afsOrder.VendorStoreID)
|
||||
if afsOrder.VendorStoreID != "" {
|
||||
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, afsOrder.VendorStoreID, 0); err == nil {
|
||||
afsOrder.JxStoreID = storeDetail.Store.ID
|
||||
}
|
||||
}
|
||||
if afsOrder.StoreID == 0 && afsOrder.JxStoreID == 0 {
|
||||
if order, err2 := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); err2 == nil {
|
||||
afsOrder.JxStoreID = order.JxStoreID
|
||||
if afsOrder.StoreID == 0 {
|
||||
afsOrder.StoreID = order.StoreID
|
||||
}
|
||||
if afsOrder.VendorStoreID == "" {
|
||||
afsOrder.VendorStoreID = order.VendorStoreID
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if err = c.updateAfsOrderSkuOtherInfo(db, afsOrder); err == nil {
|
||||
jxutils.RefreshAfsOrderSkuRelated(afsOrder)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) UpdateAfsOrderFields(afsOrder *model.AfsOrder, fieldList []string) (err error) {
|
||||
db := orm.NewOrm()
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Update(afsOrder, fieldList...)
|
||||
return err
|
||||
}, "UpdateAfsOrderFields orderID:%s failed with error:%v", afsOrder.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) setAfsOrderID(db *dao.DaoDB, orderStatus *model.OrderStatus) {
|
||||
// globals.SugarLogger.Debugf("setAfsOrderID1 orderStatus:%v", utils.Format4Output(orderStatus, true))
|
||||
if dao.IsVendorThingIDEmpty(orderStatus.VendorOrderID) {
|
||||
index := 1
|
||||
if afsOrderList, err2 := dao.GetAfsOrders(db, orderStatus.RefVendorID, orderStatus.RefVendorOrderID, ""); err2 == nil {
|
||||
if len(afsOrderList) > 0 {
|
||||
list := strings.Split(afsOrderList[0].AfsOrderID, "-")
|
||||
if len(list) > 1 {
|
||||
index = int(utils.Str2Int64WithDefault(list[1], 0))
|
||||
if afsOrderList[0].Status >= model.AfsOrderStatusFinished {
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("setAfsOrderID err2:%v", err2)
|
||||
}
|
||||
orderStatus.VendorOrderID = composeAfsOrderID(orderStatus.RefVendorOrderID, index)
|
||||
}
|
||||
// globals.SugarLogger.Debugf("setAfsOrderID2 orderStatus:%v", utils.Format4Output(orderStatus, true))
|
||||
}
|
||||
|
||||
func composeAfsOrderID(vendorOrderID string, index int) (afsOrderID string) {
|
||||
return strings.Join([]string{
|
||||
vendorOrderID,
|
||||
utils.Int2Str(index),
|
||||
}, "-")
|
||||
}
|
||||
|
||||
func (c *OrderManager) CreateAfsOrderFromOrder(vendorOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
order, err := c.LoadOrder(vendorOrderID, vendorID)
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(order, false))
|
||||
if err == nil {
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: vendorID,
|
||||
VendorOrderID: vendorOrderID,
|
||||
JxStoreID: order.JxStoreID,
|
||||
VendorStoreID: order.VendorStoreID,
|
||||
StoreID: order.StoreID,
|
||||
VendorOrgCode: order.VendorOrgCode,
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("CreateAfsOrderFromOrder, orderID:%s is not found from partner.CurOrderManager.LoadOrder", vendorOrderID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, sku := range order.Skus {
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrderID: sku.VendorOrderID,
|
||||
// OrderFinancialID: sku.VendorOrderID,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorStoreID: afsOrder.VendorStoreID,
|
||||
StoreID: afsOrder.StoreID,
|
||||
JxStoreID: afsOrder.JxStoreID,
|
||||
VendorSkuID: sku.VendorSkuID,
|
||||
SkuID: sku.SkuID,
|
||||
PromotionType: sku.PromotionType,
|
||||
Name: sku.SkuName,
|
||||
ShopPrice: sku.ShopPrice,
|
||||
SalePrice: sku.SalePrice,
|
||||
Count: sku.Count,
|
||||
// UserMoney: sku.UserMoney,
|
||||
// PmSubsidyMoney: sku.PmSubsidyMoney,
|
||||
IsAfsOrder: 1,
|
||||
}
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
|
||||
}
|
||||
return afsOrder, nil
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
COMMENT_NOT_RESOLVED = 0 //未解决的差评状态
|
||||
COMMENT_RESOLVED = 1 //已解决的差评状态
|
||||
|
||||
JX_BAD_COMMENTS_MAX_LEVEL = 2 // 差评最大分
|
||||
JX_MIDDLE_COMMENTS_MAX_LEVEL = 4 // 中评最大分
|
||||
|
||||
COMMENTS_SCORE_ONE_ORTWO_BEGIN_DELAY_TIME = 1 * 60 //评论回复一星或二星回复延迟开始时间区间
|
||||
COMMENTS_SCORE_ONE_ORTWO_END_DELAY_TIME = 3 * 60 //评论回复一星或二星回复延迟结束时间区间
|
||||
COMMENTS_SCORE_THREE_BEGIN_DELAY_TIME = 2 * 60 //评论回复三星回复延迟开始时间区间
|
||||
COMMENTS_SCORE_THREE_END_DELAY_TIME = 4 * 60 //评论回复三星回复延迟结束时间区间
|
||||
COMMENTS_SCORE_FOUR_ORFIVE_BEGIN_DELAY_TIME = 2 * 60 //评论回复四星或五星回复延迟开始时间区间
|
||||
COMMENTS_SCORE_FOUR_ORFIVE_END_DELAY_TIME = 5 * 60 //评论回复四星或五星回复延迟结束时间区间
|
||||
|
||||
MAX_REAPLY_TIME = 18 * time.Hour
|
||||
)
|
||||
|
||||
type tReplyConfig struct {
|
||||
delayGapBegin int
|
||||
delayGapEnd int
|
||||
comments []string
|
||||
}
|
||||
|
||||
var (
|
||||
replyConfig = map[int]*tReplyConfig{
|
||||
1: &tReplyConfig{
|
||||
delayGapBegin: COMMENTS_SCORE_ONE_ORTWO_BEGIN_DELAY_TIME,
|
||||
delayGapEnd: COMMENTS_SCORE_ONE_ORTWO_END_DELAY_TIME,
|
||||
comments: []string{
|
||||
"非常抱歉让您没有得到十分满意的购物体验,我们会及时与您联系进行确认并解决问题!",
|
||||
},
|
||||
},
|
||||
3: &tReplyConfig{
|
||||
delayGapBegin: COMMENTS_SCORE_THREE_BEGIN_DELAY_TIME,
|
||||
delayGapEnd: COMMENTS_SCORE_THREE_END_DELAY_TIME,
|
||||
comments: []string{
|
||||
"感谢您对我们的肯定,祝您生活愉快!欢迎再次光临,谢谢!",
|
||||
fmt.Sprintf("感谢您对%s的关照,我们会更加精益求精。", globals.StoreName),
|
||||
"感谢您的光临,您的支持是我们前进的动力!",
|
||||
},
|
||||
},
|
||||
4: &tReplyConfig{
|
||||
delayGapBegin: COMMENTS_SCORE_FOUR_ORFIVE_BEGIN_DELAY_TIME,
|
||||
delayGapEnd: COMMENTS_SCORE_FOUR_ORFIVE_END_DELAY_TIME,
|
||||
comments: []string{
|
||||
"感谢您的信赖!我们会不断提升菜品质量以及优质的服务,期待与您的再次相遇!",
|
||||
"感谢您的支持,愿您天天好心情!",
|
||||
"感谢您的认可!您的支持是我们前进的动力。",
|
||||
"感谢您的肯定与支持!我们会坚持把最好的服务带给您,期待和您的再次相遇!",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func (c *OrderManager) OnOrderComments(orderCommentList []*model.OrderComment) (err error) {
|
||||
globals.SugarLogger.Debug("OnOrderComments")
|
||||
db := dao.GetDB()
|
||||
for _, orderComment := range orderCommentList {
|
||||
globals.SugarLogger.Debugf("OnOrderComments, orderID:%s", orderComment.VendorOrderID)
|
||||
comment2 := &legacymodel.JxBadComments{
|
||||
OrderId: orderComment.VendorOrderID,
|
||||
}
|
||||
err = dao.GetEntity(db, comment2, "OrderId")
|
||||
if err == nil || dao.IsNoRowsError(err) {
|
||||
isNewComment := false
|
||||
if dao.IsNoRowsError(err) {
|
||||
err = nil
|
||||
isNewComment = true
|
||||
if orderComment.IsReplied == 0 && time.Now().Sub(orderComment.CommentCreatedAt) < time.Duration(orderComment.ModifyDuration)*time.Hour {
|
||||
if storeDetail, err2 := dao.GetStoreDetail(db, orderComment.StoreID, orderComment.VendorID); err2 == nil {
|
||||
if storeDetail.AutoReplyType == model.AutoReplyAll ||
|
||||
orderComment.Score > JX_BAD_COMMENTS_MAX_LEVEL && storeDetail.AutoReplyType == model.AutoReplyGoodComment {
|
||||
c.replyOrderComment(storeDetail.VendorOrgCode, orderComment)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if isNewComment /*&& orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL*/ || !isNewComment && orderComment.Score > JX_BAD_COMMENTS_MAX_LEVEL { // 如果是直接非差评,或补评仍然是差评,忽略
|
||||
if isNewComment {
|
||||
comment2.Createtime = utils.Time2Str(orderComment.CommentCreatedAt)
|
||||
comment2.Score = int(orderComment.Score)
|
||||
comment2.Scorecontent = orderComment.Content
|
||||
comment2.Vendertags = orderComment.TagList
|
||||
comment2.Msg = orderComment.OriginalMsg
|
||||
|
||||
comment2.Status = COMMENT_NOT_RESOLVED
|
||||
comment2.OrderFlag = utils.Int2Str(orderComment.VendorID)
|
||||
comment2.Maxmodifytime = int(orderComment.ModifyDuration)
|
||||
|
||||
order, _ := partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
|
||||
if order != nil {
|
||||
orderComment.StoreID = jxutils.GetSaleStoreIDFromOrder(order)
|
||||
if order.ConsigneeMobile2 != "" {
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile2
|
||||
} else {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
|
||||
order.ConsigneeMobile = order2.ConsigneeMobile
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"ConsigneeMobile"})
|
||||
}
|
||||
}
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile
|
||||
}
|
||||
} else {
|
||||
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, orderComment.VendorStoreID, orderComment.VendorID); err == nil {
|
||||
orderComment.StoreID = storeDetail.ID
|
||||
}
|
||||
}
|
||||
if orderComment.StoreID > 0 {
|
||||
comment2.Jxstoreid = utils.Int2Str(orderComment.StoreID)
|
||||
}
|
||||
comment2.Userphone = orderComment.ConsigneeMobile
|
||||
if comment2.Jxstoreid != "" && orderComment.Score <= JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < MAX_REAPLY_TIME {
|
||||
comment2.LastPushTime = utils.Time2Str(time.Now())
|
||||
comment2.PushNo = 1
|
||||
weixinmsg.PushJDBadCommentToWeiXin(comment2, orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL, order)
|
||||
}
|
||||
} else { // 修改评价,高于JX_BAD_COMMENTS_MAX_LEVEL
|
||||
if orderComment.CommentCreatedAt.Sub(str2Time(comment2.Createtime)) == 0 ||
|
||||
orderComment.CommentCreatedAt.Sub(str2Time(comment2.Updatetime)) == 0 {
|
||||
comment2 = nil // 重复
|
||||
} else {
|
||||
comment2.Updatetime = utils.Time2Str(orderComment.CommentCreatedAt)
|
||||
comment2.UpdatedMsg = orderComment.OriginalMsg
|
||||
comment2.UpdatedScore = int(orderComment.Score)
|
||||
comment2.UpdatedScorecontent = orderComment.Content
|
||||
comment2.UpdatedVendertags = orderComment.TagList
|
||||
comment2.Status = COMMENT_RESOLVED
|
||||
|
||||
if comment2.Jxstoreid != "" && orderComment.Score <= JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < MAX_REAPLY_TIME {
|
||||
comment2.LastPushTime = utils.Time2Str(time.Now())
|
||||
comment2.PushNo++
|
||||
|
||||
comment3 := *comment2
|
||||
comment3.Createtime = comment2.Updatetime
|
||||
comment3.Score = comment2.UpdatedScore
|
||||
comment3.Scorecontent = comment2.UpdatedScorecontent
|
||||
comment3.Vendertags = comment2.UpdatedVendertags
|
||||
order, _ := partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
|
||||
weixinmsg.PushJDBadCommentToWeiXin(&comment3, orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL, order)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if isNewComment {
|
||||
err = dao.CreateEntity(db, comment2)
|
||||
} else if comment2 != nil {
|
||||
_, err = dao.UpdateEntity(db, comment2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("OnOrderComments orderID:%s failed with error:%v", orderComment.VendorOrderID, err)
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) replyOrderComment(vendorOrgCode string, orderComment *model.OrderComment) (err error) {
|
||||
score := int(orderComment.Score)
|
||||
if score <= 2 {
|
||||
score = 1
|
||||
} else if score >= 5 {
|
||||
score = 4
|
||||
}
|
||||
config := replyConfig[score]
|
||||
delaySeconds := config.delayGapBegin + rand.Intn(config.delayGapEnd-config.delayGapBegin)
|
||||
content := config.comments[rand.Intn(len(config.comments))]
|
||||
globals.SugarLogger.Debugf("replyOrderComment orderID:%s, delaySeconds:%d, content:%s", orderComment.VendorOrderID, delaySeconds, content)
|
||||
utils.AfterFuncWithRecover(time.Duration(delaySeconds)*time.Second, func() {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(orderComment.VendorID); handler != nil {
|
||||
if err = handler.ReplyOrderComment(jxcontext.AdminCtx, vendorOrgCode, orderComment, content); err != nil {
|
||||
globals.SugarLogger.Debugf("replyOrderComment orderID:%s, error:%v", orderComment.VendorOrderID, err)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("replyOrderComment can not find handler orderID:%s", orderComment.VendorOrderID)
|
||||
}
|
||||
})
|
||||
// todo 这里直接延时,可以导致服务器重启时漏掉回复,但如果用管理任务,又会导致大量评价任务存在与任务列表中
|
||||
// task := tasksch.NewParallelTask(fmt.Sprintf("回复订单:%s评价", orderComment.VendorOrderID), nil, jxcontext.AdminCtx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// return retVal, err
|
||||
// }, []int{0})
|
||||
// tasksch.HandleTask(task, nil, true).Run()
|
||||
return err
|
||||
}
|
||||
|
||||
func str2Time(timeStr string) time.Time {
|
||||
if timeStr == "" {
|
||||
return utils.DefaultTimeValue
|
||||
}
|
||||
return utils.Str2Time(timeStr)
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
pendingOrderGapMax = 2 * 24 * time.Hour // 每次重启机子时,要检查几天内的订单状态
|
||||
maxTimeHandlePendingOrder = 2 * time.Second //处理pending order的最长时间
|
||||
maxSleepGapHandlePendingOrder = 5 * time.Millisecond // 每个pending order的最长时间间隙
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCanNotFindOrder = errors.New("找不到相应订单")
|
||||
ErrCanNotFindWaybill = errors.New("找不到相应运单")
|
||||
)
|
||||
|
||||
var (
|
||||
FixedOrderManager *OrderManager
|
||||
)
|
||||
|
||||
// 所有公共接口调用前,要求在order里或status中设置合适的Status
|
||||
type OrderManager struct {
|
||||
}
|
||||
|
||||
func NewOrderManager() *OrderManager {
|
||||
return &OrderManager{}
|
||||
}
|
||||
|
||||
type IStatusTimer interface {
|
||||
GetStatusTime() time.Time
|
||||
}
|
||||
|
||||
type StatusTimerSlice []IStatusTimer
|
||||
|
||||
func (s StatusTimerSlice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s StatusTimerSlice) Less(i, j int) bool {
|
||||
return s[i].GetStatusTime().Sub(s[j].GetStatusTime()) < 0
|
||||
}
|
||||
|
||||
func (s StatusTimerSlice) Swap(i, j int) {
|
||||
tmp := s[i]
|
||||
s[i] = s[j]
|
||||
s[j] = tmp
|
||||
}
|
||||
|
||||
func init() {
|
||||
FixedOrderManager = NewOrderManager()
|
||||
partner.InitOrderManager(FixedOrderManager)
|
||||
}
|
||||
|
||||
func addOrderOrWaybillStatus(status *model.OrderStatus, db *dao.DaoDB) (isDuplicated bool, err error) {
|
||||
if status.OrderType == model.OrderTypeOrder {
|
||||
globals.SugarLogger.Debugf("addOrderStatus order:%v", status)
|
||||
} else if status.OrderType == model.OrderTypeWaybill {
|
||||
globals.SugarLogger.Debugf("addOrderStatus waybill:%v", status)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("addOrderStatus afsOrder:%v", status)
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
globals.SugarLogger.Debug("rollback")
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
status.ID = 0
|
||||
status.Remark = utils.LimitUTF8StringLen(status.Remark, 255)
|
||||
created, _, err := db.Db.ReadOrCreate(status, "VendorOrderID", "VendorID", "OrderType", "Status", "VendorStatus", "StatusTime")
|
||||
if err == nil {
|
||||
if !created {
|
||||
globals.SugarLogger.Debugf("duplicated event:%v", status)
|
||||
isDuplicated = true
|
||||
status.DuplicatedCount++
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(status, "DuplicatedCount")
|
||||
return err
|
||||
}, "addOrderOrWaybillStatus update DuplicatedCount, status:%v", status)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// todo 这里居然会有主键重复错误,逻辑上是不应该的
|
||||
globals.SugarLogger.Warnf("addOrderOrWaybillStatus status:%v, access db error:%v", status, err)
|
||||
} else {
|
||||
dao.Commit(db)
|
||||
}
|
||||
return isDuplicated, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetStatusDuplicatedCount(status *model.OrderStatus) (duplicatedCount int) {
|
||||
if status == nil {
|
||||
return 0
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err := dao.GetEntity(db, status, "VendorOrderID", "VendorID", "OrderType", "VendorStatus", "StatusTime"); err == nil {
|
||||
return status.DuplicatedCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// todo 最好还是改成全事件回放算了
|
||||
func LoadPendingOrders() {
|
||||
orders, err := dao.LoadPendingOrders(dao.GetDB(), time.Now().Add(-pendingOrderGapMax), model.OrderStatusEndBegin)
|
||||
globals.SugarLogger.Infof("LoadPendingOrders orders count:%d, err:%v", len(orders), err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ordersCount := len(orders)
|
||||
if ordersCount > 0 {
|
||||
bills := FixedOrderManager.LoadPendingWaybills()
|
||||
globals.SugarLogger.Infof("LoadPendingOrders waybills count:%d", len(bills))
|
||||
var sortOrders StatusTimerSlice
|
||||
orderMap := make(map[string]*model.GoodsOrder)
|
||||
for _, order := range orders {
|
||||
if order.Status > model.OrderStatusNew {
|
||||
status := model.Order2Status(order)
|
||||
sortOrders = append(sortOrders, status)
|
||||
}
|
||||
// order.Status = model.OrderStatusNew // 就是要以实际order状态来调用scheduler.OnOrderNew
|
||||
order.StatusTime = order.OrderCreatedAt
|
||||
sortOrders = append(sortOrders, order)
|
||||
orderMap[jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)] = order
|
||||
}
|
||||
for _, bill := range bills {
|
||||
if bill.Status > model.WaybillStatusNew {
|
||||
bill2 := *bill
|
||||
sortOrders = append(sortOrders, &bill2)
|
||||
}
|
||||
bill.Status = model.WaybillStatusNew
|
||||
bill.StatusTime = bill.WaybillCreatedAt
|
||||
sortOrders = append(sortOrders, bill)
|
||||
}
|
||||
sort.Sort(sortOrders)
|
||||
sleepGap := maxTimeHandlePendingOrder / time.Duration(ordersCount)
|
||||
if sleepGap > maxSleepGapHandlePendingOrder {
|
||||
sleepGap = maxSleepGapHandlePendingOrder
|
||||
}
|
||||
lastTime := time.Now()
|
||||
for _, item := range sortOrders {
|
||||
if order, ok := item.(*model.GoodsOrder); ok {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
scheduler.CurrentScheduler.OnOrderNew(order, true)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
|
||||
} else if status, ok := item.(*model.OrderStatus); ok {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
order := orderMap[jxutils.ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)]
|
||||
scheduler.CurrentScheduler.OnOrderStatusChanged(order, status, true)
|
||||
}, jxutils.ComposeUniversalOrderID(status.RefVendorOrderID, status.RefVendorID))
|
||||
} else {
|
||||
bill := item.(*model.Waybill)
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, true)
|
||||
}, jxutils.ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID))
|
||||
}
|
||||
curTime := time.Now()
|
||||
timeout := sleepGap - curTime.Sub(lastTime)
|
||||
if timeout > 0 {
|
||||
time.Sleep(timeout)
|
||||
}
|
||||
lastTime = curTime
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
@@ -1,265 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
var (
|
||||
waybillOrderStatusMap = map[int]int{
|
||||
model.WaybillStatusApplyFailedGetGoods: model.OrderStatusApplyFailedGetGoods,
|
||||
model.WaybillStatusAgreeFailedGetGoods: model.OrderStatusAgreeFailedGetGoods,
|
||||
model.WaybillStatusRefuseFailedGetGoods: model.OrderStatusRefuseFailedGetGoods,
|
||||
model.WaybillStatusDeliverFailed: model.OrderStatusDeliverFailed,
|
||||
}
|
||||
complaintReasonsMap = map[int]string{
|
||||
1: "骑手态度恶劣",
|
||||
2: "骑手接单后未取货",
|
||||
3: "骑手取货太慢",
|
||||
4: "骑手送货太慢",
|
||||
5: "货品未送达",
|
||||
6: "货品有损坏",
|
||||
7: "骑手违规收取顾客其他费用",
|
||||
69: "骑手恶意取消订单",
|
||||
71: "骑手提前点击取货/送达",
|
||||
}
|
||||
)
|
||||
|
||||
func (w *OrderManager) LoadPendingWaybills() []*model.Waybill {
|
||||
db := orm.NewOrm()
|
||||
var bills []*model.Waybill
|
||||
tillTime := time.Now().Add(-pendingOrderGapMax)
|
||||
_, err := db.Raw(`
|
||||
SELECT t1.*
|
||||
FROM waybill t1
|
||||
JOIN goods_order t2 ON t2.vendor_order_id = t1.vendor_order_id
|
||||
AND t2.vendor_id = t1.order_vendor_id
|
||||
AND t2.order_created_at >= ?
|
||||
AND t2.status < ?
|
||||
WHERE t1.waybill_created_at >= ?
|
||||
AND t1.status < ?
|
||||
`, tillTime, model.OrderStatusEndBegin, tillTime, model.WaybillStatusEndBegin).QueryRows(&bills)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("LoadPendingWaybills load pending waybills error:%v", err)
|
||||
return nil
|
||||
}
|
||||
return bills
|
||||
}
|
||||
|
||||
func (w *OrderManager) onWaybillNew(bill2 *model.Waybill, db *dao.DaoDB) (isDuplicated bool, err error) {
|
||||
globals.SugarLogger.Debugf("onWaybillNew bill:%v", bill2)
|
||||
isDuplicated, err = addOrderOrWaybillStatus(model.Waybill2Status(bill2), db)
|
||||
if err == nil && !isDuplicated {
|
||||
bill2.ID = 0
|
||||
bill2.WaybillCreatedAt = bill2.StatusTime
|
||||
bill2.WaybillFinishedAt = utils.DefaultTimeValue
|
||||
billCopied := *bill2
|
||||
bill := &billCopied
|
||||
created, _, err2 := db.Db.ReadOrCreate(bill, "VendorWaybillID", "WaybillVendorID")
|
||||
if err = err2; err == nil {
|
||||
if !created {
|
||||
bill.DuplicatedCount++
|
||||
if bill2.VendorOrderID == bill2.VendorWaybillID { // 购物平台(比如京东)重新建的运单,单号始终是与订单相同的
|
||||
globals.SugarLogger.Infof("onWaybillNew duplicated1, DuplicatedCount:%d, bill:%v msg received", bill2.DuplicatedCount, bill2)
|
||||
bill2.ID = bill.ID
|
||||
bill2.CreatedAt = bill.CreatedAt
|
||||
bill2.DuplicatedCount = bill.DuplicatedCount
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(bill2) //更新所有字段
|
||||
return err
|
||||
}, "onWaybillNew Update1")
|
||||
} else {
|
||||
globals.SugarLogger.Infof("onWaybillNew duplicated2 DuplicatedCount:%d, bill:%v msg received", bill.DuplicatedCount, bill2)
|
||||
isDuplicated = true
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(bill, "DuplicatedCount")
|
||||
return err
|
||||
}, "onWaybillNew Update2")
|
||||
}
|
||||
} else {
|
||||
*bill2 = *bill
|
||||
globals.SugarLogger.Debugf("onWaybillNew created bill:%v", bill2)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("onWaybillNew create bill:%v, error:%v", bill2, err)
|
||||
}
|
||||
}
|
||||
return isDuplicated, err
|
||||
}
|
||||
|
||||
func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
|
||||
var isDuplicated bool
|
||||
if bill.ActualFee == 0 {
|
||||
bill.ActualFee = bill.DesiredFee + bill.TipFee
|
||||
}
|
||||
bill.CourierMobile = jxutils.FormalizeMobile(bill.CourierMobile)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
duplicatedCount := 0
|
||||
if bill.Status == model.WaybillStatusNew {
|
||||
isDuplicated, err = w.onWaybillNew(bill, db)
|
||||
if isDuplicated {
|
||||
duplicatedCount = 1
|
||||
}
|
||||
} else {
|
||||
existingBill, err2 := w.LoadWaybill(bill.VendorWaybillID, bill.WaybillVendorID)
|
||||
// todo
|
||||
if err2 == nil {
|
||||
bill.DeliveryFlag = existingBill.DeliveryFlag
|
||||
}
|
||||
if bill.Status == model.WaybillStatusAccepted { // 处理美团配送丢失新运单消息的情况
|
||||
if err2 != nil {
|
||||
if dao.IsNoRowsError(err2) || err2 == ErrCanNotFindWaybill {
|
||||
existingBill = bill
|
||||
billCopy := *bill
|
||||
billCopy.Status = model.WaybillStatusNew
|
||||
if isDuplicated, err = w.onWaybillNew(&billCopy, db); err != nil {
|
||||
dao.Rollback(db)
|
||||
return err
|
||||
}
|
||||
dao.Commit(db)
|
||||
// 进运单调度器OnWaybillStatusChanged之前要确保事务是提交了的,否则会导致死锁
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(&billCopy, false)
|
||||
dao.Begin(db)
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
return err2
|
||||
}
|
||||
}
|
||||
// 运单消息错序,之前已经结束了,直接返回
|
||||
if existingBill.Status >= model.WaybillStatusEndBegin {
|
||||
dao.Commit(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
addParams := orm.Params{}
|
||||
if bill.Status >= model.WaybillStatusAccepted {
|
||||
if bill.Status == model.WaybillStatusAccepted {
|
||||
if bill.DesiredFee > 0 {
|
||||
addParams["desired_fee"] = bill.DesiredFee
|
||||
}
|
||||
if bill.ActualFee > 0 {
|
||||
addParams["actual_fee"] = bill.ActualFee
|
||||
}
|
||||
}
|
||||
if bill.CourierMobile != "" {
|
||||
addParams["courier_name"] = bill.CourierName
|
||||
addParams["courier_mobile"] = bill.CourierMobile
|
||||
}
|
||||
if bill.Status >= model.WaybillStatusEndBegin {
|
||||
addParams["waybill_finished_at"] = bill.StatusTime
|
||||
}
|
||||
}
|
||||
duplicatedCount, err = w.addWaybillStatus(bill, db, addParams)
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
if duplicatedCount == 0 {
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, false)
|
||||
}
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
}
|
||||
if bill.VendorOrderID == bill.VendorWaybillID {
|
||||
if status, ok := waybillOrderStatusMap[bill.Status]; ok {
|
||||
fakeOrderStatus := &model.OrderStatus{
|
||||
VendorOrderID: bill.VendorOrderID,
|
||||
VendorID: bill.OrderVendorID,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: bill.VendorOrderID,
|
||||
RefVendorID: bill.OrderVendorID,
|
||||
Status: status,
|
||||
VendorStatus: bill.VendorStatus,
|
||||
StatusTime: bill.StatusTime,
|
||||
Remark: bill.Remark,
|
||||
}
|
||||
w.OnOrderStatusChanged(bill.VendorOrgCode, fakeOrderStatus)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *OrderManager) addWaybillStatus(bill *model.Waybill, db *dao.DaoDB, addParams orm.Params) (duplicatedCount int, err error) {
|
||||
waybillStatus := model.Waybill2Status(bill)
|
||||
isDuplicated, err := addOrderOrWaybillStatus(waybillStatus, db)
|
||||
if err == nil && !isDuplicated {
|
||||
if waybillStatus.Status > model.WaybillStatusUnknown { // todo 这里应该和addOrderStatus一样的改法,状态不能回绕
|
||||
params := utils.MergeMaps(orm.Params{
|
||||
"status": bill.Status,
|
||||
"vendor_status": bill.VendorStatus,
|
||||
"status_time": bill.StatusTime,
|
||||
}, addParams)
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.QueryTable("waybill").Filter("vendor_waybill_id", bill.VendorWaybillID).Filter("waybill_vendor_id", bill.WaybillVendorID).Filter("status__lte", bill.Status).Update(params)
|
||||
return err
|
||||
}, "addWaybillStatus update waybill status, bill:%v", bill)
|
||||
} else {
|
||||
duplicatedCount = -1
|
||||
}
|
||||
} else {
|
||||
duplicatedCount = 1
|
||||
}
|
||||
return duplicatedCount, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) LoadWaybill(vendorWaybillID string, waybillVendorID int) (bill *model.Waybill, err error) {
|
||||
db := orm.NewOrm()
|
||||
bill = &model.Waybill{
|
||||
VendorWaybillID: vendorWaybillID,
|
||||
WaybillVendorID: waybillVendorID,
|
||||
}
|
||||
if err = db.Read(bill, "VendorWaybillID", "WaybillVendorID"); err != nil {
|
||||
bill = nil
|
||||
if err == orm.ErrNoRows {
|
||||
err = ErrCanNotFindWaybill
|
||||
}
|
||||
globals.SugarLogger.Infof("LoadWaybill vendorWaybillID:%s failed with error:%v", vendorWaybillID, err)
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
|
||||
func GetComplaintReasons() (complaintReasonList []*dadaapi.ComplaintReason) {
|
||||
for k, v := range complaintReasonsMap {
|
||||
complaintReason := &dadaapi.ComplaintReason{
|
||||
ID: k,
|
||||
Reason: v,
|
||||
}
|
||||
complaintReasonList = append(complaintReasonList, complaintReason)
|
||||
}
|
||||
return complaintReasonList
|
||||
}
|
||||
|
||||
func ComplaintRider(ctx *jxcontext.Context, vendorOrderID string, vendorID, waybillVendorID, complaintID int) (err error) {
|
||||
db := dao.GetDB()
|
||||
p := partner.GetDeliveryPlatformFromVendorID(waybillVendorID).Handler
|
||||
wayBillList, err := dao.GetWayBillByOrderID(db, 0, vendorID, waybillVendorID, vendorOrderID)
|
||||
if err == nil && len(wayBillList) > 0 {
|
||||
err = p.ComplaintRider(wayBillList[0], complaintID, complaintReasonsMap[complaintID])
|
||||
} else {
|
||||
return fmt.Errorf("未查询到到相关订单!订单号:[%v] ,厂商:[%v],运送厂商:[%v]", vendorOrderID, vendorID, waybillVendorID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
package basesch
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
var (
|
||||
FixedBaseScheduler *BaseScheduler
|
||||
)
|
||||
|
||||
type BaseScheduler struct {
|
||||
IsReallyCallPlatformAPI bool
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusNew || order.Status == model.OrderStatusWaitAccepted {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AcceptOrRefuseOrder(order, isAcceptIt, userName)
|
||||
}, "AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
|
||||
}
|
||||
} else {
|
||||
return scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("AcceptOrRefuseOrder orderID:%s, status:%d is not suitable, isAcceptIt:%t", order.VendorOrderID, order.Status, isAcceptIt)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("PickupGoods orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusAccepted {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID)
|
||||
err = utils.CallFuncLogErrorWithInfo(func() (err error) {
|
||||
if err = handler.PickupGoods(order, isSelfDelivery, userName); err != nil {
|
||||
if status, err2 := handler.GetOrderStatus(order.VendorOrgCode, order.VendorOrderID); err2 == nil && status >= model.OrderStatusFinished {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}, "PickupGoods orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusAccepted {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("PickupGoods orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("PickupGoods orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status >= model.OrderStatusFinishedPickup && order.Status <= model.OrderStatusDelivering {
|
||||
if order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled == 0 && c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).Swtich2SelfDeliver(order, userName)
|
||||
}, "Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
if err == nil { // 因为有些平台转自送后,不会再发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup || order.VendorID == order.WaybillVendorID {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("Swtich2SelfDeliver orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusDelivering {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).Swtich2SelfDelivered(order, userName)
|
||||
}, "Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("Swtich2SelfDelivered orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("Swtich2SelfDelivered orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusFinishedPickup {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivering(order, userName)
|
||||
}, "SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if err == nil { // 因为有些平台设置配送中后,不会发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("SelfDeliverDelivering orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("SelfDeliverDelivering orderID:%s, status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliverDelivered orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status >= model.OrderStatusFinishedPickup &&
|
||||
order.Status <= model.OrderStatusDelivering {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivered(order, userName)
|
||||
}, "SelfDeliverDelivered orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("SelfDeliverDelivered orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("SelfDeliverDelivered orderID:%s, status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
|
||||
globals.SugarLogger.Infof("CreateWaybill orderID:%s, vendor:%s", order.VendorOrderID, jxutils.GetVendorName(platformVendorID))
|
||||
if !model.IsOrderSolid(order) { // 如果订单是不完整的
|
||||
globals.SugarLogger.Warnf("CreateWaybill orderID:%s, vendorID:%d is not solid!!!", order.VendorOrderID, platformVendorID)
|
||||
return nil, scheduler.ErrOrderIsNotSolid
|
||||
}
|
||||
// if order.DeliveryFlag&model.OrderDeliveryFlagMaskScheduleDisabled != 0 {
|
||||
// waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(jxcontext.AdminCtx, order.VendorOrderID, order.VendorID, true)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// if len(waybillList) > 0 {
|
||||
// return nil, fmt.Errorf("转商家自送的订单只允许有一个有效运单,当前已经有%s运单", jxutils.GetVendorName(waybillList[0].WaybillVendorID))
|
||||
// }
|
||||
// }
|
||||
handlerInfo := partner.GetDeliveryPlatformFromVendorID(platformVendorID)
|
||||
if handlerInfo != nil && handlerInfo.Use4CreateWaybill {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
bill, err = handlerInfo.Handler.CreateWaybill(order, maxDeliveryFee)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("CreateWaybill failed orderID:%s vendorID:%d with error:%v", order.VendorOrderID, platformVendorID, err)
|
||||
} else {
|
||||
order.DeliveryFlag |= model.WaybillVendorID2Mask(platformVendorID)
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrDeliverProviderWrong
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
globals.SugarLogger.Infof("CancelWaybill bill:%v, cancelReasonID:%d cancelReason:%s", bill, cancelReasonID, cancelReason)
|
||||
// 部分快递平台在取消成功后有时会不发运单取消消息过来(比如达达,904200512000442),为避免二次取消报错,添加状态判断
|
||||
if c.IsReallyCallPlatformAPI && bill.OrderVendorID != bill.WaybillVendorID && bill.Status != model.WaybillStatusCanceled {
|
||||
if handlerInfo := partner.GetDeliveryPlatformFromVendorID(bill.WaybillVendorID); handlerInfo != nil {
|
||||
if err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return handlerInfo.Handler.CancelWaybill(bill, cancelReasonID, cancelReason)
|
||||
}, "CancelWaybill bill:%v", bill); err == nil {
|
||||
bill.Status = model.WaybillStatusCanceled
|
||||
bill.DeliveryFlag |= model.WaybillDeliveryFlagMaskActiveCancel
|
||||
_, err = dao.UpdateEntity(nil, bill, "Status", "DeliveryFlag")
|
||||
}
|
||||
globals.SugarLogger.Debugf("CancelWaybill bill:%v canceled by myself", bill)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,422 +0,0 @@
|
||||
package basesch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
autoSelfTakeCode = "135246"
|
||||
)
|
||||
|
||||
func (c *BaseScheduler) CreateWaybillOnProviders(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs, excludeCourierVendorIDs []int, maxDeliveryFee int64, createOnlyOne bool) (bills []*model.Waybill, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
globals.SugarLogger.Infof("CreateWaybillOnProviders orderID:%s userName:%s, courierVendorIDs:%v, excludeCourierVendorIDs:%v", order.VendorOrderID, userName, courierVendorIDs, excludeCourierVendorIDs)
|
||||
storeCourierList, err := dao.GetStoreCourierList(dao.GetDB(), []int{jxutils.GetSaleStoreIDFromOrder(order)}, nil, model.StoreStatusOpened, model.StoreAuditStatusOnline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
courierVendorIDMap := jxutils.IntList2Map(courierVendorIDs)
|
||||
excludeCourierVendorIDMap := jxutils.IntList2Map(excludeCourierVendorIDs)
|
||||
errList := errlist.New()
|
||||
for _, storeCourier := range storeCourierList {
|
||||
if (courierVendorIDs == nil || courierVendorIDMap[storeCourier.VendorID] == 1) &&
|
||||
(excludeCourierVendorIDs == nil || excludeCourierVendorIDMap[storeCourier.VendorID] == 0) {
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil && handler.Use4CreateWaybill {
|
||||
courierVendorID := storeCourier.VendorID
|
||||
bill, err2 := c.CreateWaybill(courierVendorID, order, maxDeliveryFee)
|
||||
if err = err2; err == nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d bill:%v", order.VendorOrderID, userName, courierVendorID, bill)
|
||||
bills = append(bills, bill)
|
||||
if createOnlyOne {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d failed with error:%v", order.VendorOrderID, userName, courierVendorID, err)
|
||||
errList.AddErr(fmt.Errorf("平台:%s,%s", jxutils.GetVendorName(courierVendorID), err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(bills) > 0 {
|
||||
err = errList.GetErrListAsOne()
|
||||
if err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "创建三方运单部分失败", err.Error())
|
||||
}
|
||||
err = nil
|
||||
} else if errList.GetErrListAsOne() == nil {
|
||||
err = fmt.Errorf("orderID:%s没有绑定有效的三方配送门店或没有剩下可用的三方配送", order.VendorOrderID)
|
||||
} else {
|
||||
err = fmt.Errorf("orderID:%s所有运单失败:%s", order.VendorOrderID, errList.GetErrListAsOne().Error())
|
||||
}
|
||||
globals.SugarLogger.Infof("CreateWaybillOnProviders orderID:%s userName:%s error:%v", order.VendorOrderID, userName, err)
|
||||
return bills, err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliveredAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
if model.IsOrderDeliveryByStore(order) {
|
||||
err = c.SelfDeliverDelivered(order, userName)
|
||||
} else if model.IsOrderDeliveryByPlatform(order) {
|
||||
err = c.Swtich2SelfDelivered(order, userName)
|
||||
}
|
||||
if err == nil {
|
||||
// order.Status = model.OrderStatusFinished // todo 是否需要强制设置完成状态?
|
||||
if err = dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskSetDelivered); err == nil {
|
||||
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PickupGoodsAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
err = c.PickupGoods(order, model.IsOrderDeliveryByStore(order), userName)
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusFinishedPickup
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AdjustOrder(ctx, order, removedSkuList, reason)
|
||||
if err == nil {
|
||||
var skuIDs []string
|
||||
for _, v := range removedSkuList {
|
||||
skuIDs = append(skuIDs, utils.Int2Str(v.SkuID))
|
||||
}
|
||||
noticeMsg := fmt.Sprintf("商品skuID列表:%v,订单号(点击进入详情):%v", strings.Join(skuIDs, ","), globals.BackstageHost+"/#/ordermanager/"+order.VendorOrderID)
|
||||
user, err := dao.GetUserByID(dao.GetDB(), "mobile", "18982250714")
|
||||
if user != nil && err == nil {
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "调整单调整商品", noticeMsg)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
if globals.IsAddEvent {
|
||||
err = cms.AddEventDetail(dao.GetDB(), ctx, model.OperateUpdate, order.StoreID, model.ThingTypeOrder, order.StoreID, order.VendorOrderID, order.StoreName)
|
||||
}
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).CancelOrder(ctx, order, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AcceptOrRefuseFailedGetOrder(ctx, order, isAcceptIt)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.OrderFlagAgreeFailedGetGoods
|
||||
if !isAcceptIt {
|
||||
flag = model.OrderFlagRefuseFailedGetGoods
|
||||
}
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, flag)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CallPMCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).CallCourier(ctx, order)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskCallPMCourier)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).ConfirmReceiveGoods(ctx, order)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskFailedDeliver)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AgreeOrRefuseCancel(ctx, order, isAcceptIt, reason)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.OrderFlagAgreeUserApplyCancel
|
||||
if !isAcceptIt {
|
||||
flag = model.OrderFlagRefuseUserApplyCancel
|
||||
}
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, flag)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelWaybillByID(ctx *jxcontext.Context, vendorWaybillID string, waybillVendorID int, cancelReasonID int, cancelReason string) (err error) {
|
||||
bill, err := partner.CurOrderManager.LoadWaybill(vendorWaybillID, waybillVendorID)
|
||||
if err == nil {
|
||||
err = c.CancelWaybill(bill, cancelReasonID, cancelReason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AgreeOrRefuseRefund(ctx *jxcontext.Context, afsOrderID string, vendorID, approveType int, reason string) (err error) {
|
||||
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
|
||||
if err == nil {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(vendorID).AgreeOrRefuseRefund(ctx, afsOrder, approveType, reason)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.AfsOrderFlagAgreeUserRefund
|
||||
if approveType == partner.AfsApproveTypeRefused {
|
||||
flag = model.AfsOrderFlagRefuseUserRefund
|
||||
afsOrder.RefuseReason = reason
|
||||
partner.CurOrderManager.UpdateAfsOrderFields(afsOrder, []string{"RefuseReason"})
|
||||
} else {
|
||||
if order, _ := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
|
||||
if order.EarningType == model.EarningTypePoints {
|
||||
var (
|
||||
skuMap = make(map[int]*model.OrderSku)
|
||||
diff int64
|
||||
db = dao.GetDB()
|
||||
)
|
||||
for _, sku := range order.Skus {
|
||||
skuMap[sku.SkuID] = sku
|
||||
}
|
||||
storeDetail, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID)
|
||||
waybills, _ := dao.GetWaybills(db, order.VendorOrderID)
|
||||
//京东商城和京西要重新算totalshopmoney等
|
||||
if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
|
||||
skus, _ := dao.GetAfsOrderSkuInfo(db, order.VendorOrderID, afsOrderID, order.VendorID, false)
|
||||
for _, v := range skus {
|
||||
if skuMap[v.SkuID] != nil {
|
||||
diff += skuMap[v.SkuID].SalePrice * int64(v.Count)
|
||||
}
|
||||
}
|
||||
order.TotalShopMoney = utils.Float64TwoInt64(float64(float64(order.TotalShopMoney)/jdshopapi.JdsPayPercentage-float64(diff)) * jdshopapi.JdsPayPercentage)
|
||||
if len(waybills) > 0 {
|
||||
jxutils.RefreshOrderEarningPrice3(order, storeDetail.PayPercentage, waybills[0])
|
||||
} else {
|
||||
jxutils.RefreshOrderEarningPrice2(order, storeDetail.PayPercentage)
|
||||
}
|
||||
dao.UpdateEntity(db, order, "TotalShopMoney", "NewEarningPrice")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, flag)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, afsOrderID string, vendorID int) (err error) {
|
||||
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
|
||||
if err == nil {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(vendorID).ConfirmReceivedReturnGoods(ctx, afsOrder)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, model.AfsOrderFlagMaskReturnGoods)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).PartRefundOrder(ctx, order, refundSkuList, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).RefundOrder(ctx, order, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmSelfTake(ctx *jxcontext.Context, vendorOrderID string, vendorID int, selfTakeCode string) (err error) {
|
||||
order, err2 := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
err = c.confirmSelfTake(ctx, order, selfTakeCode)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SetOrderWaybillTip(ctx *jxcontext.Context, vendorOrderID string, vendorID int, tipFee int64) (err error) {
|
||||
order, err2 := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
err = c.SetOrderWaybillTipByOrder(ctx, order, tipFee)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isWaybillCanAddTip(waybill *model.Waybill) (isCan bool) {
|
||||
isCan = waybill.Status >= model.WaybillStatusNew && waybill.Status < model.WaybillStatusAccepted && partner.GetWaybillTipUpdater(waybill.WaybillVendorID) != nil
|
||||
return isCan
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SetOrderWaybillTipByOrder(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) {
|
||||
roundTipFee := tipFee / 100 * 100
|
||||
if roundTipFee != tipFee {
|
||||
return fmt.Errorf("小费必须是1元的整数倍")
|
||||
}
|
||||
if order.WaybillTipMoney >= tipFee {
|
||||
return fmt.Errorf("当前小费已经是%s元,想要设置%s元", jxutils.IntPrice2StandardString(order.WaybillTipMoney), jxutils.IntPrice2StandardString(tipFee))
|
||||
}
|
||||
|
||||
db := dao.GetDB()
|
||||
storeDetail, err2 := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID)
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果平台支持设置配送小费,必须要成功设置
|
||||
if handler := partner.GetWaybillTipUpdater(order.VendorID); handler != nil {
|
||||
if err = handler.UpdateWaybillTip(ctx, order.VendorOrgCode, order.VendorStoreID, order.VendorOrderID, "", "", utils.Int2Str(storeDetail.CityCode), tipFee); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
order.WaybillTipMoney = tipFee
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"WaybillTipMoney"})
|
||||
|
||||
waybills, err := dao.GetWayBillByOrderID(db, 0, order.VendorID, 0, order.VendorOrderID)
|
||||
if err == nil {
|
||||
var waybills2 []*model.Waybill
|
||||
for _, v := range waybills {
|
||||
// 必须是三方配送
|
||||
if !model.IsWaybillPlatformOwn(v) && isWaybillCanAddTip(v) {
|
||||
waybills2 = append(waybills2, v)
|
||||
}
|
||||
}
|
||||
if len(waybills2) > 0 {
|
||||
task := tasksch.NewParallelTask("SetOrderWaybillTipByOrder", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
waybill := batchItemList[0].(*model.Waybill)
|
||||
handler := partner.GetWaybillTipUpdater(waybill.WaybillVendorID)
|
||||
if err == nil {
|
||||
err = handler.UpdateWaybillTip(ctx, waybill.VendorOrgCode, storeDetail.VendorStoreID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), tipFee)
|
||||
}
|
||||
return nil, err
|
||||
}, waybills2)
|
||||
tasksch.HandleTask(task, nil, false).Run()
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) confirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) {
|
||||
globals.SugarLogger.Debugf("confirmSelfTake orderID:%s, selfTakeCode:%s", order.VendorOrderID, selfTakeCode)
|
||||
vendorID := order.VendorID
|
||||
if vendorID == model.VendorIDJD || vendorID == model.VendorIDJX {
|
||||
if vendorID == model.VendorIDJD {
|
||||
if selfTakeCode == autoSelfTakeCode {
|
||||
if selfTakeCode, err = jd.CurPurchaseHandler.GetSelfTakeCode(ctx, order); err != nil {
|
||||
return fmt.Errorf("获取订单:%s自提货码失败,原始错误:%s", order.VendorOrderID, err.Error())
|
||||
}
|
||||
if selfTakeCode == "" {
|
||||
return fmt.Errorf("订单:%s看起来不是一个自提订单,如果确认是自提订单,请联系开发", order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
err = jd.CurPurchaseHandler.ConfirmSelfTake(ctx, order, selfTakeCode)
|
||||
} else {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
VendorID: model.VendorIDJX,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
RefVendorID: model.VendorIDJX,
|
||||
VendorStatus: utils.Int2Str(model.OrderStatusFinished),
|
||||
Status: model.OrderStatusFinished,
|
||||
StatusTime: time.Now(),
|
||||
Remark: "自提完成",
|
||||
}
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged("", orderStatus)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, model.VendorIDJX))
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("自提核销不支持%s平台订单", model.VendorChineseNames[order.VendorID])
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmSelfTakeOrders(ctx *jxcontext.Context, vendorIDs []int, orderCreatedAfter, orderCreatedBefore time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
orderList, err := dao.GetPendingFakeOrders(dao.GetDB(), vendorIDs, orderCreatedAfter, orderCreatedBefore)
|
||||
if err == nil {
|
||||
if len(orderList) > 0 {
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("自动完成内部自提单%v,%s", vendorIDs, utils.Time2Str(orderCreatedAfter)), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
order := batchItemList[0].(*model.GoodsOrder)
|
||||
if order.Status == model.OrderStatusAccepted {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
err = handler.AcceptOrRefuseOrder(order, true, ctx.GetUserName())
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if err = c.confirmSelfTake(ctx, order, autoSelfTakeCode); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, orderList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,59 +0,0 @@
|
||||
package defsch
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
push "git.rosy.net.cn/jx-callback/business/jxutils/unipush"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/msghub"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
var (
|
||||
autoRejectSkuMap = map[int]int{
|
||||
33996: 1,
|
||||
33995: 1,
|
||||
33994: 1,
|
||||
33991: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (s *DefScheduler) OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error) {
|
||||
if order.Status == model.AfsOrderStatusWait4Approve {
|
||||
if !isPending {
|
||||
if isAutoRejectAfsOrder(order) {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if err := handler.AgreeOrRefuseRefund(jxcontext.AdminCtx, order, partner.AfsApproveTypeRefused, "抱歉,蟹券不接受退货或换货"); err != nil {
|
||||
globals.SugarLogger.Debugf("OnAfsOrderNew, orderID:%s, afsOrderID:%s failed with err:%v", order.VendorOrderID, order.AfsOrderID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
msghub.OnNewWait4ApproveAfsOrder(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
push.NotifyAfsOrder(order)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error) {
|
||||
if status.Status == model.AfsOrderStatusWait4ReceiveGoods {
|
||||
if !isPending {
|
||||
msghub.OnKeyAfsOrderStatusChanged(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isAutoRejectAfsOrder(order *model.AfsOrder) (isReject bool) {
|
||||
for _, v := range order.Skus {
|
||||
if autoRejectSkuMap[jxutils.GetSkuIDFromOrderSkuFinancial(v)] == 1 {
|
||||
isReject = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return isReject
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
package defsch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func (s *DefScheduler) loadSavedOrderByID(vendorOrderID string, vendorID int, isForceLoad bool) *WatchOrderInfo {
|
||||
return s.loadSavedOrderFromMap(&model.OrderStatus{
|
||||
RefVendorOrderID: vendorOrderID,
|
||||
RefVendorID: vendorID,
|
||||
}, isForceLoad)
|
||||
}
|
||||
|
||||
func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
var order *model.GoodsOrder
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
order = savedOrderInfo.order
|
||||
if err = s.isPossibleSwitch2SelfDelivery(order); err == nil {
|
||||
err = s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
|
||||
if err == nil {
|
||||
if model.IsOrderDeliveryByStore(order) {
|
||||
if order.Status < model.OrderStatusDelivering {
|
||||
storeDetail, err2 := dao.GetStoreDetail(dao.GetDB(), order.StoreID, order.VendorID)
|
||||
phone := userName
|
||||
if err = err2; err == nil {
|
||||
phone = storeDetail.Tel1
|
||||
}
|
||||
err = s.SelfDeliverDelivering(order, phone)
|
||||
}
|
||||
} else {
|
||||
if order.Status < model.OrderStatusDelivering {
|
||||
err = s.Swtich2SelfDeliver(order, userName)
|
||||
} else if order.VendorID == order.WaybillVendorID { // 状态为配送中,且是购物平台运单,不能转自送了
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled | model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: vendorOrderID,
|
||||
VendorID: vendorID,
|
||||
}
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
vendorStatus := fmt.Sprintf("%s转商户自送成功", ctx.GetUserName())
|
||||
remark := ""
|
||||
if err != nil {
|
||||
vendorStatus = fmt.Sprintf("%s转商户自送失败", ctx.GetUserName())
|
||||
remark = err.Error()
|
||||
}
|
||||
partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) canOrderCreateWaybillNormally(order *model.GoodsOrder, savedOrderInfo *WatchOrderInfo) (err error) {
|
||||
if !(order.LockStatus != model.OrderStatusLocked && order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) {
|
||||
err = fmt.Errorf("当前订单%s没有处于拣货完成且没有结束没有锁定的订单才能进行召唤配送操作", order.VendorOrderID)
|
||||
} else if model.IsOrderHaveWaybill(order) {
|
||||
err = fmt.Errorf("当前订单%s已经有了有效的承运人%s了", order.VendorOrderID, jxutils.GetVendorName(order.WaybillVendorID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) isPossibleSwitch2SelfDelivery(order *model.GoodsOrder) (err error) {
|
||||
if model.IsOrderDeliveryByPlatform(order) {
|
||||
if order.Status < model.OrderStatusFinishedPickup {
|
||||
err = fmt.Errorf("拣货完成后才能转自配送")
|
||||
} else if order.Status == model.OrderStatusFinishedPickup {
|
||||
if time.Now().Sub(order.StatusTime) < minMinute2Schedule3rdCarrier*time.Minute {
|
||||
err = fmt.Errorf("非自配送门店转3方配送至少要求拣货完成后%d分钟才能操作", minMinute2Schedule3rdCarrier)
|
||||
}
|
||||
} else if order.Status >= model.OrderStatusDelivering && order.Status < model.OrderStatusEndBegin {
|
||||
if model.IsOrderHaveOwnWaybill(order) {
|
||||
err = fmt.Errorf("%s物流已在配送中,不能转自配送", jxutils.GetVendorName(order.VendorID))
|
||||
}
|
||||
} else if order.Status >= model.OrderStatusEndBegin {
|
||||
err = fmt.Errorf("订单%s已经结束,请刷新状态", order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) CreateWaybillOnProviders4SavedOrder(ctx *jxcontext.Context, savedOrderInfo *WatchOrderInfo, courierVendorIDs, excludeCourierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, err error) {
|
||||
order := savedOrderInfo.order
|
||||
if !forceCreate {
|
||||
err = s.canOrderCreateWaybillNormally(order, nil)
|
||||
}
|
||||
if err == nil {
|
||||
if forceCreate {
|
||||
maxDeliveryFee = math.MaxInt64
|
||||
}
|
||||
if bills, err = s.CreateWaybillOnProviders(ctx, order, courierVendorIDs, excludeCourierVendorIDs, maxDeliveryFee, forceCreate); err == nil {
|
||||
if forceCreate {
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
if err == nil {
|
||||
if forceCreate {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
}
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders4SavedOrder orderID:%s userName:%s successfully", order.VendorOrderID, ctx.GetUserName())
|
||||
return bills, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders4SavedOrder orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) CreateWaybillOnProvidersEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int, courierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
bills, err = func() (bills []*model.Waybill, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProvidersEx orderID:%s userName:%s", vendorOrderID, userName)
|
||||
if vendorID == model.VendorIDELM {
|
||||
return nil, fmt.Errorf("不要直接使用饿了么订单号,请使用相应的饿百订单号")
|
||||
}
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
order := savedOrderInfo.order
|
||||
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
|
||||
return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID)
|
||||
}
|
||||
if !forceCreate {
|
||||
err = s.isPossibleSwitch2SelfDelivery(order)
|
||||
}
|
||||
if err == nil {
|
||||
if bills, err = s.CreateWaybillOnProviders4SavedOrder(ctx, savedOrderInfo, courierVendorIDs, nil, forceCreate, maxDeliveryFee); err == nil && len(bills) > 0 {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "手动创建运单成功", fmt.Sprintf("%s创建%s平台运单,强发:%t,最高限价:%d", ctx.GetUserName(), model.VendorChineseNames[bills[0].WaybillVendorID], forceCreate, maxDeliveryFee))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
globals.SugarLogger.Infof("CreateWaybillOnProvidersEx orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
|
||||
return bills, err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return bills, err
|
||||
}
|
||||
|
||||
// todo 这个函数可以和SelfDeliveringAndUpdateStatus合并
|
||||
func (s *DefScheduler) CancelAll3rdWaybills(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isStopSchedule bool) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s", vendorOrderID, ctx.GetUserName())
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
err = s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
|
||||
} else {
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s error:%v", vendorOrderID, ctx.GetUserName(), err)
|
||||
if err == nil && isStopSchedule {
|
||||
order := savedOrderInfo.order
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s successfully", vendorOrderID, ctx.GetUserName())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) QueryOrderWaybillFeeInfoEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
deliveryFeeMap, err = func() (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
globals.SugarLogger.Infof("GetWaybillsInfoEx orderID:%s userName:%s", vendorOrderID, userName)
|
||||
|
||||
db := dao.GetDB()
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
|
||||
return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID)
|
||||
}
|
||||
storeCourierList, err := dao.GetStoreCourierList(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, nil, model.StoreStatusAll, model.StoreAuditStatusOnline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(ctx, vendorOrderID, vendorID, true, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waybillMap := make(map[int]*model.Waybill)
|
||||
for _, bill := range waybillList {
|
||||
waybillMap[bill.WaybillVendorID] = &bill.Waybill
|
||||
}
|
||||
deliveryFeeMap = make(map[int]*partner.WaybillFeeInfo)
|
||||
|
||||
var timeoutSecond int
|
||||
if savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, false); savedOrderInfo != nil {
|
||||
timeoutSecond = savedOrderInfo.GetCreateWaybillTimeout()
|
||||
}
|
||||
for _, storeCourier := range storeCourierList {
|
||||
var feeInfo *partner.WaybillFeeInfo
|
||||
if waybillMap[storeCourier.VendorID] != nil {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
Waybill: waybillMap[storeCourier.VendorID],
|
||||
}
|
||||
} else {
|
||||
if storeCourier.Status != model.StoreStatusOpened {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierNotOpen,
|
||||
ErrStr: fmt.Sprintf("暂未开通,联系运营"),
|
||||
}
|
||||
} else {
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil {
|
||||
if handler.Use4CreateWaybill {
|
||||
if feeInfo, err = handler.Handler.GetWaybillFee(order); err != nil {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierOthers,
|
||||
ErrStr: err.Error(),
|
||||
}
|
||||
} else {
|
||||
feeInfo.TimeoutSecond = timeoutSecond
|
||||
}
|
||||
} else {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierForbidden,
|
||||
ErrStr: fmt.Sprintf("内部错误,%d不能用于创建运单", storeCourier.VendorID),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierNotSupported,
|
||||
ErrStr: fmt.Sprintf("内部错误,%d不被支持", storeCourier.VendorID),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
deliveryFeeMap[storeCourier.VendorID] = feeInfo
|
||||
}
|
||||
err = nil
|
||||
return deliveryFeeMap, err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return deliveryFeeMap, err
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
const (
|
||||
StoreDeliveryTypeCrowdSourcing = 0 //缺省,平台众包配送,可转自送
|
||||
StoreDeliveryTypeByPlatform = 1 //平台专送
|
||||
StoreDeliveryTypeByStore = 2 //完全门店自送,这个表示的意思是平台的门店属性(就是购物平台不负责配送),而不是真正是否是老板自己送
|
||||
)
|
||||
|
||||
const (
|
||||
TimerStatusTypeUnknown = -1
|
||||
TimerStatusTypeOrder = 0
|
||||
TimerStatusTypeWaybill = 1
|
||||
)
|
||||
|
||||
var (
|
||||
CurrentScheduler IScheduler
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOrderStatusIsNotSuitable4CurOperation = errors.New("订单锁定或状态不适合当前操作")
|
||||
ErrOrderStatusAlreadySatisfyCurOperation = errors.New("订单当前状态已满足当前操作")
|
||||
|
||||
ErrCanNotCreateAtLeastOneWaybill = errors.New("一个运单都不能创建")
|
||||
ErrCanNotFindOrder = errors.New("不能找到订单(一般是由于事件错序)")
|
||||
ErrCanNotFindWaybill = errors.New("不能找到运单(一般是由于事件错序)")
|
||||
ErrOrderIsNotSolid = errors.New("订单是临时订单,不完整,不能用于创建运单")
|
||||
ErrDeliverProviderWrong = errors.New("快递商不存在或不能用于创建运单")
|
||||
)
|
||||
|
||||
type IScheduler interface {
|
||||
// 以下是订单
|
||||
OnOrderNew(order *model.GoodsOrder, isPending bool) (err error)
|
||||
OnOrderStatusChanged(order *model.GoodsOrder, status *model.OrderStatus, isPending bool) (err error)
|
||||
|
||||
// 以下是运单
|
||||
OnWaybillStatusChanged(bill *model.Waybill, isPending bool) (err error)
|
||||
|
||||
// 以下是售后单
|
||||
OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error)
|
||||
OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,209 +0,0 @@
|
||||
package act
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestInitDb(t *testing.T) {
|
||||
dao.ExecuteSQL(dao.GetDB(), `
|
||||
DROP TABLE IF EXISTS act, act_map, act_order_rule, act_store_sku, act_store_sku_map;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestCreateActOnAlpha(t *testing.T) {
|
||||
actStoreSkuList := []*ActStoreSkuParam{
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 2142,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1162,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1167,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1172,
|
||||
},
|
||||
},
|
||||
}
|
||||
t.Log(utils.Format4Output(actStoreSkuList, true))
|
||||
// actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
|
||||
// Name: "测试活动",
|
||||
// PricePercentage: 80,
|
||||
// Type: model.ActSkuDirectDown,
|
||||
// }, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}, nil, actStoreSkuList, false)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// globals.SugarLogger.Debug(actID)
|
||||
}
|
||||
|
||||
func TestCreateActOnDev(t *testing.T) {
|
||||
actStoreSkuList := []*ActStoreSkuParam{
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22716,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22717,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100920,
|
||||
SkuID: 22714,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100920,
|
||||
SkuID: 22715,
|
||||
},
|
||||
},
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 26595,
|
||||
// },
|
||||
// },
|
||||
}
|
||||
// t.Log(utils.Format4Output(actStoreSkuList, true))
|
||||
actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
|
||||
Name: "测试活动",
|
||||
PricePercentage: 80,
|
||||
Type: model.ActSkuDirectDown,
|
||||
BeginAt: time.Now().Add(-24 * time.Hour),
|
||||
EndAt: time.Now().Add(10 * 24 * time.Hour),
|
||||
}, []int{model.VendorIDJD, model.VendorIDMTWM /*, model.VendorIDEBAI*/}, nil, actStoreSkuList, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
globals.SugarLogger.Debug(actID)
|
||||
}
|
||||
|
||||
func TestCancelAct(t *testing.T) {
|
||||
err := CancelAct(jxcontext.AdminCtx, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteActStoreBind(t *testing.T) {
|
||||
_, err := DeleteActStoreSkuBind(jxcontext.AdminCtx, dao.GetDB(), 1, []*ActStoreSkuParam{
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30828,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30827,
|
||||
// },
|
||||
// },
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22716,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22717,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddActStoreBind(t *testing.T) {
|
||||
err := AddActStoreSkuBind(jxcontext.AdminCtx, dao.GetDB(), 1, []*ActStoreSkuParam{
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30828,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30827,
|
||||
// },
|
||||
// },
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22716,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22717,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncAct(t *testing.T) {
|
||||
_, err := SyncAct(jxcontext.AdminCtx, nil, 1, nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestForceUpdateVendorPrice(t *testing.T) {
|
||||
hint, err := ForceUpdateVendorPrice(jxcontext.AdminCtx, model.VendorIDJD, model.ActSkuDirectDown, []*ActStoreSkuParam{
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100118,
|
||||
SkuID: 22509,
|
||||
ActPrice: 9900,
|
||||
},
|
||||
VendorPrice: 19900,
|
||||
},
|
||||
}, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(hint)
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
)
|
||||
|
||||
// todo 是否需要将Store.MarketManPhone与OperatorPhone成角色?
|
||||
|
||||
func TransferLegacyWeixins(mobile string) (err error) {
|
||||
globals.SugarLogger.Debugf("TransferLegacyWeixins mobile:%s", mobile)
|
||||
if !globals.EnableWXAuth2 || globals.DisableWXAuth1 {
|
||||
return nil
|
||||
}
|
||||
remark4Transfer := "transfer"
|
||||
// DELETE t1
|
||||
// FROM auth_bind t1
|
||||
// WHERE t1.remark = 'transfer';
|
||||
|
||||
// DELETE t1
|
||||
// FROM user t1
|
||||
// WHERE t1.remark = 'transfer';
|
||||
|
||||
// TRUNCATE TABLE casbin_rule;
|
||||
|
||||
sql := `
|
||||
SELECT t1.*
|
||||
FROM weixins t1
|
||||
LEFT JOIN user t2 ON t2.mobile = t1.tel
|
||||
LEFT JOIN auth_bind t3 ON t3.auth_id = t1.openid AND t3.type = 'weixinsns'
|
||||
LEFT JOIN auth_bind t4 ON t4.auth_id = t1.openid_mini AND t4.type = 'weixinmini'
|
||||
WHERE`
|
||||
sqlParams := []interface{}{}
|
||||
if mobile != "" {
|
||||
remark4Transfer = "transfer2"
|
||||
sql += " t1.tel = ?"
|
||||
sqlParams = append(sqlParams, mobile)
|
||||
} else {
|
||||
sql += " t2.id IS NULL OR (t1.openid <> '' AND t3.id IS NULL) OR (t1.openid_mini <> '' AND t4.id IS NULL)"
|
||||
}
|
||||
sql += " ORDER BY t1.parentid;"
|
||||
var weixinList []*legacymodel.WeiXins
|
||||
db := dao.GetDB()
|
||||
err = dao.GetRows(db, &weixinList, sql, sqlParams...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parentMap := make(map[int]*legacymodel.WeiXins)
|
||||
for _, v := range weixinList {
|
||||
if v.ParentID == -1 {
|
||||
parentMap[v.ID] = v
|
||||
} else {
|
||||
if parentMap[v.ParentID] != nil {
|
||||
v.JxStoreID = parentMap[v.ParentID].JxStoreID
|
||||
}
|
||||
}
|
||||
if v.Tel != "" {
|
||||
user := &model.User{
|
||||
UserID2: v.Tel,
|
||||
Name: v.NickName,
|
||||
Mobile: &v.Tel,
|
||||
Type: model.UserTypeStoreBoss,
|
||||
Remark: remark4Transfer,
|
||||
}
|
||||
if user.Name == "" {
|
||||
user.Name = user.GetMobile()
|
||||
}
|
||||
userList, _, err2 := dao.GetUsers(db, 0, "", nil, nil, []string{v.Tel}, 0, -1)
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(user, false))
|
||||
if len(userList) == 0 {
|
||||
err = CreateUser(user, v.LastOperator)
|
||||
} else {
|
||||
user = userList[0]
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.OpenID != "" {
|
||||
auth2.AddAuthBind(user, &auth2.AuthInfo{
|
||||
AuthBindInfo: &auth2.AuthBindEx{
|
||||
AuthBind: model.AuthBind{
|
||||
Type: weixin.AuthTypeMP,
|
||||
AuthID: v.OpenID,
|
||||
AuthID2: v.OpenIDUnion,
|
||||
Remark: remark4Transfer,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if v.OpenIDMini != "" {
|
||||
auth2.AddAuthBind(user, &auth2.AuthInfo{
|
||||
AuthBindInfo: &auth2.AuthBindEx{
|
||||
AuthBind: model.AuthBind{
|
||||
Type: weixin.AuthTypeMini,
|
||||
AuthID: v.OpenIDMini,
|
||||
AuthID2: v.OpenIDUnion,
|
||||
Remark: remark4Transfer,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if v.JxStoreID > 0 { // 运营就不加到门店老板组里了
|
||||
if user.Type&model.UserTypeOperator == 0 {
|
||||
api2.RoleMan.AddRole4User(user.GetID(), autils.NewStoreBossRole(v.JxStoreID))
|
||||
}
|
||||
} else {
|
||||
if mobile != "" {
|
||||
rList, err2 := api2.RoleMan.GetUserRoleList(user.GetID())
|
||||
if err = err2; err == nil {
|
||||
for _, role := range rList {
|
||||
if role.StoreID > 0 {
|
||||
api2.RoleMan.DeleteRole4User(user.GetID(), autils.NewStoreBossRole(role.StoreID))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func TestTransferLegacyWeixins(t *testing.T) {
|
||||
err := TransferLegacyWeixins("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCasbin(t *testing.T) {
|
||||
userList, err := api2.RoleMan.GetRoleUserList(autils.NewStoreBossRole(100324))
|
||||
t.Log(utils.Format4Output(userList, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -2,30 +2,17 @@ package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -42,60 +29,7 @@ type SysConfigLimit struct {
|
||||
|
||||
var (
|
||||
serviceInfo map[string]interface{}
|
||||
allowUpdatePlaceFieldsMap = map[string]bool{
|
||||
"name": true,
|
||||
"enabled": true,
|
||||
"mtpsPrice": true,
|
||||
}
|
||||
|
||||
regexpMsgContentOpID = regexp.MustCompile(`"openid":"(.*?)"`)
|
||||
|
||||
receiveMsgUsersMap = map[string][]string{
|
||||
SendMsgTypeOpenStoreRequest: []string{
|
||||
"石锋",
|
||||
// "x",
|
||||
// "周扬",
|
||||
},
|
||||
SendMsgTypeSuggestRequest: []string{
|
||||
"石锋",
|
||||
// "x",
|
||||
// "周扬",
|
||||
// "苏尹岚",
|
||||
},
|
||||
}
|
||||
needConfirmRequestMap = map[string]int{
|
||||
SendMsgTypeOpenStoreRequest: 1,
|
||||
}
|
||||
|
||||
SysConfigLimitMap = map[string]*SysConfigLimit{
|
||||
model.ConfigSysEbaiBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 500,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDEBAI}, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
model.ConfigSysMtwmBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 500,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDMTWM}, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
model.ConfigSysMtwmSkuBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 50,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDMTWM, nil, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
|
||||
@@ -109,46 +43,41 @@ 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,
|
||||
"unionActTypeNames": map[int]map[int]interface{}{
|
||||
model.VendorIDMTWM: map[int]interface{}{
|
||||
mtunionapi.ActTypeQB: "券包推广",
|
||||
},
|
||||
//model.VendorIDTB: map[int]interface{}{
|
||||
// tbunionapi.TbElmActTypeBDH: "本地化",
|
||||
//},
|
||||
//model.VendorIDPDD: map[int]interface{}{
|
||||
// 1: "进行中的活动",
|
||||
//},
|
||||
model.VendorIDJDShop: map[int]interface{}{
|
||||
2: "进行中",
|
||||
},
|
||||
},
|
||||
"unionOrderStatusName": model.UnionOrderStatusName,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -190,213 +119,15 @@ func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, par
|
||||
return places, dao.GetRows(nil, &places, sql, sqlParams)
|
||||
}
|
||||
|
||||
func UpdatePlaces(ctx *jxcontext.Context, places []map[string]interface{}, userName string) (num int64, err error) {
|
||||
if len(places) == 0 {
|
||||
return 0, ErrMissingInput
|
||||
}
|
||||
updateFields := []string{}
|
||||
for k := range places[0] {
|
||||
if allowUpdatePlaceFieldsMap[k] {
|
||||
updateFields = append(updateFields, k)
|
||||
}
|
||||
}
|
||||
for _, place := range places {
|
||||
if place["code"] == nil {
|
||||
return 0, ErrMissingInput
|
||||
}
|
||||
placeid := &model.Place{}
|
||||
valid := dao.NormalMakeMapByFieldList(place, updateFields, userName)
|
||||
if num, err = dao.UpdateEntityLogically(nil, placeid, valid, userName, utils.Params2Map("Code", place["code"])); err != nil {
|
||||
return num, err
|
||||
}
|
||||
}
|
||||
return num, err
|
||||
}
|
||||
|
||||
func UpdatePlace(ctx *jxcontext.Context, placeCode int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||||
payload["code"] = placeCode
|
||||
return UpdatePlaces(ctx, []map[string]interface{}{payload}, userName)
|
||||
}
|
||||
|
||||
func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
|
||||
return api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat), nil
|
||||
}
|
||||
|
||||
func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name string, err error) {
|
||||
name, _ = api.AutonaviAPI.GetCoordinateCityInfo(lng, lat)
|
||||
return name, err
|
||||
}
|
||||
|
||||
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
|
||||
if needConfirmRequestMap[msgType] == 1 {
|
||||
if _, err = mobile.AutherObj.VerifySecret(mobileNum, verifyCode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
db := dao.GetDB()
|
||||
//获取门店信息
|
||||
var (
|
||||
stores []*model.Store
|
||||
authBinds []*model.AuthBind
|
||||
order *model.GoodsOrder
|
||||
storeName string
|
||||
storeID int
|
||||
vendorOrderID string
|
||||
)
|
||||
if mobileNum != "" {
|
||||
sql := `
|
||||
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql, sqlParams)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
if storeID == 0 {
|
||||
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
|
||||
if len(results) > 0 {
|
||||
sql3 := `
|
||||
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
|
||||
`
|
||||
sqlParams3 := []interface{}{results[1], results[1]}
|
||||
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
|
||||
if len(authBinds) > 0 {
|
||||
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
|
||||
mobileNum = *user.Mobile
|
||||
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql, sqlParams4)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
|
||||
if len(results) > 0 {
|
||||
sql3 := `
|
||||
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
|
||||
`
|
||||
sqlParams3 := []interface{}{results[1], results[1]}
|
||||
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
|
||||
if len(authBinds) > 0 {
|
||||
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
|
||||
mobileNum = *user.Mobile
|
||||
sql4 := `
|
||||
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
|
||||
`
|
||||
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql4, sqlParams4)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sql2 := `
|
||||
SELECT *
|
||||
FROM goods_order
|
||||
WHERE IF(store_id <> '', store_id, jx_store_id) = ?
|
||||
ORDER BY order_created_at DESC
|
||||
LIMIT 1
|
||||
`
|
||||
sqlParams2 := []interface{}{storeID}
|
||||
err = dao.GetRow(db, &order, sql2, sqlParams2)
|
||||
if order != nil {
|
||||
vendorOrderID = order.VendorOrderID
|
||||
}
|
||||
if storeID == 0 {
|
||||
vendorOrderID = ""
|
||||
}
|
||||
msgContent = msgContent + " 门店名称:" + storeName + " 门店ID:" + utils.Int2Str(storeID) + " 最新订单号:" + vendorOrderID
|
||||
for _, v := range receiveMsgUsersMap[msgType] {
|
||||
user, err2 := dao.GetUserByID(db, "name", v)
|
||||
if err2 == nil {
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), msgType, msgContent)
|
||||
} else if err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func checkSysConfig(key, value string) (err error) {
|
||||
if limit := SysConfigLimitMap[key]; limit != nil {
|
||||
if limit.ValueType == reflect.Int {
|
||||
int64Value, err2 := strconv.ParseInt(value, 10, 64)
|
||||
if err = err2; err == nil {
|
||||
if int64Value < limit.MinValue || int64Value > limit.MaxValue {
|
||||
err = fmt.Errorf("配置%s,值%s超范围[%d,%d]", key, value, limit.MinValue, limit.MaxValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onSysConfigChanged(key, value string) (err error) {
|
||||
if limit := SysConfigLimitMap[key]; limit != nil && limit.AfterChanged != nil {
|
||||
err = limit.AfterChanged()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func checkConfig(opFlag int, configType, key, value string) (err error) {
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
if value != "" {
|
||||
pricePack := dao.PricePercentagePack2Obj(value)
|
||||
if pricePack == nil {
|
||||
err = fmt.Errorf("配置:%s不合法", value)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeFreightPack:
|
||||
if value != "" {
|
||||
freightPack := dao.FreightDeductionPack2Obj(value)
|
||||
if freightPack == nil {
|
||||
err = fmt.Errorf("配置:%s不合法", value)
|
||||
} else {
|
||||
var lastStage *model.FreightDeductionItem
|
||||
for _, v := range freightPack.FreightDeductionList {
|
||||
if lastStage != nil && lastStage.DeductFreight > v.DeductFreight {
|
||||
err = fmt.Errorf("免运设置不合理:门槛:%s,免运金额:%s,门槛:%s,免运金额:%s",
|
||||
jxutils.IntPrice2StandardString(int64(lastStage.BeginPrice)), jxutils.IntPrice2StandardString(int64(lastStage.DeductFreight)),
|
||||
jxutils.IntPrice2StandardString(int64(v.BeginPrice)), jxutils.IntPrice2StandardString(int64(v.DeductFreight)))
|
||||
return err
|
||||
}
|
||||
lastStage = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeBank:
|
||||
if value != "" {
|
||||
if model.BankName[key] == "" {
|
||||
err = fmt.Errorf("此银行代码:%s不支持,请联系开发", value)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeRole:
|
||||
case model.ConfigTypeSys:
|
||||
if opFlag&( /*model.SyncFlagNewMask|*/ model.SyncFlagDeletedMask) != 0 {
|
||||
err = fmt.Errorf("系统参数只支持修改或添加,不支持删除")
|
||||
} else {
|
||||
err = checkSysConfig(key, value)
|
||||
}
|
||||
case model.ConfigTypeJxStore:
|
||||
case model.ConfigTypeCookie:
|
||||
case model.ConfigTypeDiscountCard:
|
||||
default:
|
||||
err = fmt.Errorf("当前只支持配置:%s, 传入的配置类型:%s", utils.Format4Output(model.ConfigTypeName, true), configType)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
|
||||
if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
db := dao.GetDB()
|
||||
conf := &model.NewConfig{
|
||||
@@ -407,75 +138,7 @@ 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)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
db := dao.GetDB()
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
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("暂不支持删除银行")
|
||||
case model.ConfigTypeRole:
|
||||
errList := errlist.New()
|
||||
userIDs, err2 := api2.RoleMan.GetRoleUserList(autils.NewRole(key, 0))
|
||||
if err = err2; err == nil && len(userIDs) > 0 {
|
||||
userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", userIDs, nil, nil, 0, -1)
|
||||
if err = err2; err == nil && totalCount > 0 {
|
||||
// todo
|
||||
// err = fmt.Errorf("还有人员在使用角色:%s,人员信息:%s", key, utils.MustMarshal(utils.Struct2Map(userList, "compact")))
|
||||
err = fmt.Errorf("还有人员在使用角色:%s,人员信息:%s", key, utils.Format4Output(userList, false))
|
||||
}
|
||||
}
|
||||
errList.AddErr(err)
|
||||
storeList, err2 := dao.GetStoreList(db, nil, nil, nil, nil, key)
|
||||
if err = err2; err == nil && len(storeList) > 0 {
|
||||
storeIDs := make([]int, len(storeList))
|
||||
for k, v := range storeList {
|
||||
storeIDs[k] = v.ID
|
||||
}
|
||||
err = fmt.Errorf("还有门店在使用角色:%s,门店信息:%s", key, utils.MustMarshal(storeIDs))
|
||||
}
|
||||
errList.AddErr(err)
|
||||
err = errList.GetErrListAsOne()
|
||||
}
|
||||
if err == nil {
|
||||
_, err = dao.DeleteEntityLogically(db, &model.NewConfig{}, nil, ctx.GetUserName(), map[string]interface{}{
|
||||
"Key": key,
|
||||
"Type": configType,
|
||||
})
|
||||
}
|
||||
if configType == model.ConfigTypeSys && err == nil {
|
||||
err = onSysConfigChanged(key, "")
|
||||
// err = onSysConfigChanged(key, value)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -484,80 +147,35 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
|
||||
if key == "" {
|
||||
return "", fmt.Errorf("修改配置必须给定key")
|
||||
}
|
||||
if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
|
||||
return "", err
|
||||
}
|
||||
hint = "1"
|
||||
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
configList, err := dao.QueryConfigs(db, key, configType, "")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
return "", err
|
||||
}
|
||||
if _, err = dao.UpdateEntityLogically(db, configList[0], map[string]interface{}{
|
||||
"Value": value,
|
||||
}, ctx.GetUserName(), nil); err != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
return "", err
|
||||
}
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return "", err
|
||||
}
|
||||
dao.Commit(db)
|
||||
vendorStoreMap := make(map[int][]int)
|
||||
for _, v := range storeMapList {
|
||||
vendorStoreMap[v.VendorID] = append(vendorStoreMap[v.VendorID], v.StoreID)
|
||||
}
|
||||
for vendorID, storeIDs := range vendorStoreMap {
|
||||
if vendorID != model.VendorIDJX {
|
||||
dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, nil, model.SyncFlagPriceMask)
|
||||
} else {
|
||||
hint, err = ReCalculateJxPrice(db, ctx, storeIDs)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeFreightPack:
|
||||
dao.Commit(db)
|
||||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, v := range storeMapList {
|
||||
var storeMapList2 []*model.StoreMap
|
||||
if v.FreightDeductionPack == key {
|
||||
storeMapList2 = append(storeMapList2, v)
|
||||
}
|
||||
if len(storeMapList2) > 0 {
|
||||
task := tasksch.NewParallelTask("同步门店配送免运", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
_, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeMap.StoreID, false, ctx.GetUserName())
|
||||
return retVal, err
|
||||
}, storeMapList2)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if len(storeMapList2) < 5 {
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
if configType == model.ConfigTypeSys && err == nil {
|
||||
err = onSysConfigChanged(key, value)
|
||||
// err = onSysConfigChanged(key, value)
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -565,17 +183,3 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
|
||||
func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfig, err error) {
|
||||
return dao.QueryConfigs(dao.GetDB(), key, configType, keyword)
|
||||
}
|
||||
|
||||
func 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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
11
business/jxstore/cms/conn_test.go
Normal file
11
business/jxstore/cms/conn_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConn(t *testing.T) {
|
||||
err := DelPrinterSeq(1000, "120220915001012")
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
type MessageStatusExt struct {
|
||||
@@ -65,13 +65,13 @@ func GetStoreMessages(ctx *jxcontext.Context, msgIDs, storeIDs, types []int, fro
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
sqlParams = append(sqlParams, pageSize, offset)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer dao.Commit(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer dao.Commit(db, txDB)
|
||||
var msgList []*model.Message
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
if err = dao.GetRows(db, &msgList, sql, sqlParams...); err == nil {
|
||||
if err = dao.GetRowsTx(txDB, &msgList, sql, sqlParams...); err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount(db),
|
||||
TotalCount: dao.GetLastTotalRowCountTx(txDB),
|
||||
Data: msgList,
|
||||
}
|
||||
}
|
||||
@@ -120,14 +120,14 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs []int, fro
|
||||
sql += " LIMIT ? OFFSET ?"
|
||||
sqlParams = append(sqlParams, jxutils.FormalizePageSize(pageSize), offset)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer dao.Commit(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer dao.Commit(db, txDB)
|
||||
var msgStatusList []*MessageStatusExt
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
|
||||
if err = dao.GetRows(db, &msgStatusList, sql, sqlParams...); err == nil {
|
||||
if err = dao.GetRowsTx(txDB, &msgStatusList, sql, sqlParams...); err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount(db),
|
||||
TotalCount: dao.GetLastTotalRowCountTx(txDB),
|
||||
Data: msgStatusList,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package cms
|
||||
@@ -1,287 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
func GetMenu(ctx *jxcontext.Context, userID string) (menus []*model.Menu, err error) {
|
||||
if userID == "" {
|
||||
return dao.GetMenu(dao.GetDB(), "", 0, userID)
|
||||
} else {
|
||||
return dao.GetMenuWithUser(dao.GetDB(), "", 0, userID)
|
||||
}
|
||||
}
|
||||
|
||||
func AddMenu(ctx *jxcontext.Context, menu *model.Menu) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
if menu == nil {
|
||||
return fmt.Errorf("添加失败!menu nil")
|
||||
}
|
||||
if menu.Name == "" || menu.Level == 0 {
|
||||
return fmt.Errorf("添加失败!menu 名称和等级必须有值!")
|
||||
}
|
||||
menus, err := dao.GetMenu(db, menu.Name, menu.Level, "")
|
||||
if len(menus) > 0 {
|
||||
return fmt.Errorf("添加失败!已存在相同名称的 menu name : %v", menu.Name)
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
dao.WrapAddIDCULDEntity(menu, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, menu)
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateMenu(ctx *jxcontext.Context, menuID int, payload map[string]interface{}, isDelete bool) (num int64, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
menu := &model.Menu{}
|
||||
menu.ID = menuID
|
||||
err = dao.GetEntity(db, menu)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if !isDelete {
|
||||
valid := dao.StrictMakeMapByStructObject(payload, menu, ctx.GetUserName())
|
||||
if len(valid) > 0 {
|
||||
if num, err = dao.UpdateEntityLogically(db, menu, valid, ctx.GetUserName(), nil); err != nil {
|
||||
dao.Rollback(db)
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
menu.DeletedAt = time.Now()
|
||||
num, err = dao.UpdateEntity(db, menu, "DeletedAt")
|
||||
}
|
||||
dao.Commit(db)
|
||||
return num, err
|
||||
}
|
||||
|
||||
func GetRole(ctx *jxcontext.Context) (roles []*model.Role, err error) {
|
||||
return dao.GetRole(dao.GetDB(), "")
|
||||
}
|
||||
|
||||
func AddRole(ctx *jxcontext.Context, name string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
roles, err := dao.GetRole(db, name)
|
||||
if len(roles) > 0 {
|
||||
return fmt.Errorf("添加失败!已存在相同名称的 role name : %v", name)
|
||||
}
|
||||
role := &model.Role{
|
||||
Name: name,
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
dao.WrapAddIDCULDEntity(role, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, role)
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool) (num int64, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
if roleID == 1 {
|
||||
return 0, fmt.Errorf("管理员不允许修改!")
|
||||
}
|
||||
role := &model.Role{}
|
||||
role.ID = roleID
|
||||
err = dao.GetEntity(db, role)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if !isDelete {
|
||||
role.Name = name
|
||||
role.UpdatedAt = time.Now()
|
||||
role.LastOperator = ctx.GetUserName()
|
||||
num, err = dao.UpdateEntity(db, role, "Name", "UpdatedAt", "LastOperator")
|
||||
} else {
|
||||
role.DeletedAt = time.Now()
|
||||
num, err = dao.UpdateEntity(db, role, "DeletedAt")
|
||||
}
|
||||
dao.Commit(db)
|
||||
return num, err
|
||||
}
|
||||
|
||||
func GetUserRole(ctx *jxcontext.Context, userID string) (userRoles []*model.UserRole, err error) {
|
||||
return dao.GetUserRole(dao.GetDB(), []string{userID}, nil)
|
||||
}
|
||||
|
||||
func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
roleIDMap = make(map[int]int)
|
||||
nowRoleIDMap = make(map[int]int)
|
||||
userRoleMap = make(map[string][]int)
|
||||
addUserRoleMap = make(map[string][]int)
|
||||
deleteUserRoleMap = make(map[string][]int)
|
||||
)
|
||||
for _, v := range roleIDs {
|
||||
roleIDMap[v] = 1
|
||||
}
|
||||
userRoles, err := dao.GetUserRole(db, userIDs, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(userRoles) > 0 {
|
||||
for _, v := range userRoles {
|
||||
userRoleMap[v.UserID] = append(userRoleMap[v.UserID], v.RoleID)
|
||||
}
|
||||
}
|
||||
for _, userID := range userIDs {
|
||||
nowRoleIDs := userRoleMap[userID]
|
||||
for _, nowRoleID := range nowRoleIDs {
|
||||
if roleIDMap[nowRoleID] == 0 {
|
||||
deleteUserRoleMap[userID] = append(deleteUserRoleMap[userID], nowRoleID)
|
||||
}
|
||||
nowRoleIDMap[nowRoleID] = 1
|
||||
}
|
||||
for _, roleID := range roleIDMap {
|
||||
if nowRoleIDMap[roleID] == 0 {
|
||||
addUserRoleMap[userID] = append(addUserRoleMap[userID], roleID)
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if len(addUserRoleMap) > 0 {
|
||||
for userID, roleIDs := range addUserRoleMap {
|
||||
for _, roleID := range roleIDs {
|
||||
userRole := &model.UserRole{
|
||||
UserID: userID,
|
||||
RoleID: roleID,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(userRole, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, userRole)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(deleteUserRoleMap) > 0 {
|
||||
for userID, roleIDs := range deleteUserRoleMap {
|
||||
for _, roleID := range roleIDs {
|
||||
userRoles, _ := dao.GetUserRole(db, []string{userID}, []int{roleID})
|
||||
if len(userRoles) > 0 {
|
||||
userRoles[0].DeletedAt = time.Now()
|
||||
userRoles[0].LastOperator = ctx.GetUserName()
|
||||
_, err = dao.UpdateEntity(db, userRoles[0], "DeletedAt", "LastOperator")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetRoleMenu(ctx *jxcontext.Context, roleID int) (roleMenus []*model.RoleMenu, err error) {
|
||||
return dao.GetRoleMenu(dao.GetDB(), []int{roleID}, nil)
|
||||
}
|
||||
|
||||
func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
menuIDMap = make(map[int]int)
|
||||
nowMenuIDMap = make(map[int]int)
|
||||
roleMenuMap = make(map[int][]int)
|
||||
addRoleMenuMap = make(map[int][]int)
|
||||
deleteRoleMenuMap = make(map[int][]int)
|
||||
)
|
||||
for _, v := range menuIDs {
|
||||
menuIDMap[v] = 1
|
||||
}
|
||||
roleMenus, err := dao.GetRoleMenu(db, roleIDs, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(roleMenus) > 0 {
|
||||
for _, v := range roleMenus {
|
||||
roleMenuMap[v.RoleID] = append(roleMenuMap[v.RoleID], v.MenuID)
|
||||
}
|
||||
}
|
||||
for _, roleID := range roleIDs {
|
||||
nowMenuIDs := roleMenuMap[roleID]
|
||||
for _, nowMenuID := range nowMenuIDs {
|
||||
if menuIDMap[nowMenuID] == 0 {
|
||||
deleteRoleMenuMap[roleID] = append(deleteRoleMenuMap[roleID], nowMenuID)
|
||||
}
|
||||
nowMenuIDMap[nowMenuID] = 1
|
||||
}
|
||||
for _, menuID := range menuIDMap {
|
||||
if nowMenuIDMap[menuID] == 0 {
|
||||
addRoleMenuMap[menuID] = append(addRoleMenuMap[menuID], menuID)
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if len(addRoleMenuMap) > 0 {
|
||||
for roleID, menuIDs := range addRoleMenuMap {
|
||||
for _, menuID := range menuIDs {
|
||||
roleMenu := &model.RoleMenu{
|
||||
RoleID: roleID,
|
||||
MenuID: menuID,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(roleMenu, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, roleMenu)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(deleteRoleMenuMap) > 0 {
|
||||
for roleID, menuIDs := range deleteRoleMenuMap {
|
||||
for _, menuID := range menuIDs {
|
||||
roleMenus, _ := dao.GetRoleMenu(db, []int{roleID}, []int{menuID})
|
||||
if len(roleMenus) > 0 {
|
||||
roleMenus[0].DeletedAt = time.Now()
|
||||
roleMenus[0].LastOperator = ctx.GetUserName()
|
||||
_, err = dao.UpdateEntity(db, roleMenus[0], "DeletedAt", "LastOperator")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
467
business/jxstore/cms/print.go
Normal file
467
business/jxstore/cms/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/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"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 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.GetPrintMsgs(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,
|
||||
}
|
||||
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.GetPrintMsgs(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()
|
||||
)
|
||||
//看有没有
|
||||
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); 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
|
||||
}
|
||||
}
|
||||
|
||||
func connHandler(c net.Conn, printInfo *PrintInfo) (status int) {
|
||||
defer c.Close()
|
||||
//缓冲
|
||||
buf := make([]byte, 1024)
|
||||
data, _ := json.Marshal(printInfo)
|
||||
//写入数据
|
||||
c.Write(data)
|
||||
//服务器端返回的数据写入buf
|
||||
n, _ := c.Read(buf)
|
||||
status = utils.Str2Int(string(buf[:n]))
|
||||
//服务器端回传的信息
|
||||
fmt.Println("server response:", string(buf[:n]))
|
||||
return status
|
||||
}
|
||||
|
||||
//#region 打印机拼装模板
|
||||
|
||||
// QueryPrinterSetting 查询用户设置
|
||||
func QueryPrinterSetting() {
|
||||
|
||||
}
|
||||
|
||||
//#endregion 打印机
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,35 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
func TestGetStoresVendorSnapshot(t *testing.T) {
|
||||
result, err := GetStoresVendorSnapshot(jxcontext.AdminCtx, nil, []int{model.VendorIDEBAI}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
t.Log(len(result))
|
||||
}
|
||||
|
||||
func TestSendAlarmVendorSnapshot(t *testing.T) {
|
||||
db := dao.GetDB()
|
||||
prevSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-09-19 11:00:00"))
|
||||
curSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-09-19 15:00:00"))
|
||||
err := SendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, prevSnapshotList, curSnapshotList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateVendorStoreStatusBySnapshot(t *testing.T) {
|
||||
db := dao.GetDB()
|
||||
curSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-07-30 08:00:00"))
|
||||
updateVendorStoreStatusBySnapshot(db, curSnapshotList)
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
type StoreManager struct {
|
||||
}
|
||||
|
||||
var (
|
||||
FixedStoreManager *StoreManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
FixedStoreManager = &StoreManager{}
|
||||
partner.InitStoreManager(FixedStoreManager)
|
||||
}
|
||||
|
||||
func (s *StoreManager) OnStoreStatusChanged(vendorStoreID string, vendorID int, storeStatus int) (err error) {
|
||||
return err
|
||||
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeStatus:%d", vendorStoreID, storeStatus)
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, vendorStoreID, vendorID)
|
||||
if err == nil {
|
||||
var storeKV, storeMapKV map[string]interface{}
|
||||
if storeStatus == model.StoreStatusOpened {
|
||||
if storeDetail.Status != model.StoreStatusOpened {
|
||||
storeKV = map[string]interface{}{
|
||||
"Status": model.StoreStatusOpened,
|
||||
}
|
||||
}
|
||||
if storeDetail.VendorStatus != model.StoreStatusOpened {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": model.StoreStatusOpened,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if storeDetail.Status == model.StoreStatusOpened {
|
||||
if storeDetail.VendorStatus != storeStatus {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": storeStatus,
|
||||
}
|
||||
}
|
||||
} else if storeDetail.Status <= storeStatus {
|
||||
if storeDetail.VendorStatus != model.StoreStatusOpened {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": model.StoreStatusOpened,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil && (storeKV != nil || storeMapKV != nil) {
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if storeKV != nil {
|
||||
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeKV:%s", vendorStoreID, utils.Format4Output(storeKV, true))
|
||||
store := &model.Store{}
|
||||
store.ID = storeDetail.Store.ID
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntityLogically(db, store, storeKV, model.AdminName, nil)
|
||||
return err
|
||||
}, "OnStoreStatusChanged Update Store venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if storeMapKV != nil {
|
||||
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeMapKV:%s", vendorStoreID, utils.Format4Output(storeMapKV, true))
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntityLogically(db, &model.StoreMap{}, storeMapKV, model.AdminName, map[string]interface{}{
|
||||
model.FieldStoreID: storeDetail.Store.ID,
|
||||
model.FieldVendorID: vendorID,
|
||||
model.FieldDeletedAt: utils.DefaultTimeValue,
|
||||
})
|
||||
return err
|
||||
}, "OnStoreStatusChanged Update StoreMap venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if storeStatus != model.StoreStatusOpened {
|
||||
// 因为storeStatus != model.StoreStatusOpened不会修改京西门店的状态,所以直接用storeDetail.Status是合适的
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
return dao.FormalizeStoreStatus(db, storeDetail.Store.ID, storeDetail.Status)
|
||||
}, "OnStoreStatusChanged FormalizeStoreStatus venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StoreManager) OnCourierStoreStatusChanged(ctx *jxcontext.Context, vendorStoreID string, vendorID int, auditStatus int) (err error) {
|
||||
if vendorStoreID != "" {
|
||||
db := dao.GetDB()
|
||||
_, err2 := dao.GetStoreDetail2(db, 0, vendorStoreID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
status := model.StoreStatusOpened
|
||||
if auditStatus != model.StoreAuditStatusOnline {
|
||||
status = model.StoreStatusDisabled
|
||||
}
|
||||
_, err = dao.UpdateEntityLogically(db, &model.StoreCourierMap{}, map[string]interface{}{
|
||||
model.FieldStatus: status,
|
||||
"AuditStatus": auditStatus,
|
||||
}, ctx.GetUserName(), map[string]interface{}{
|
||||
model.FieldVendorStoreID: vendorStoreID,
|
||||
model.FieldVendorID: vendorID,
|
||||
})
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Debugf("OnCourierStoreStatusChanged vendorStoreID:%s, auditStatus:%d, err:%v", vendorStoreID, auditStatus, err)
|
||||
return err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,604 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
type MultiStoreVendorInfo struct {
|
||||
VendorID int
|
||||
OrgCode string
|
||||
}
|
||||
|
||||
func CombineVendorIDAndOrgCode(vendorID int, orgCode string) string {
|
||||
return fmt.Sprintf("%d-%s", vendorID, orgCode)
|
||||
}
|
||||
|
||||
func getMultiStoreVendorInfoList() (list []*MultiStoreVendorInfo) {
|
||||
vendorIDs := partner.GetMultiStoreVendorIDs()
|
||||
for _, vendorID := range vendorIDs {
|
||||
orgCodeList := partner.CurAPIManager.GetAppOrgCodeList(vendorID)
|
||||
for _, v := range orgCodeList {
|
||||
list = append(list, &MultiStoreVendorInfo{
|
||||
VendorID: vendorID,
|
||||
OrgCode: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func syncCategories(ctx *jxcontext.Context, db *dao.DaoDB, parentTask tasksch.ITask, catList []*dao.SkuStoreCatInfo, isAsync bool) (hint string, err error) {
|
||||
if len(catList) > 0 {
|
||||
// todo 按vendorID orgCode合并操作
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("同步分类2:%d", len(catList)), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
catVendorInfo := batchItemList[0].(*dao.SkuStoreCatInfo)
|
||||
if catVendorInfo.Level != 1 && catVendorInfo.ParentVendorCatID == "" {
|
||||
return nil, fmt.Errorf("%d的父目录%d没有同步", catVendorInfo.ID, catVendorInfo.ParentID)
|
||||
}
|
||||
if catVendorInfo.MapID == 0 {
|
||||
return nil, fmt.Errorf("分类:%d的数据异常", catVendorInfo.ID)
|
||||
}
|
||||
if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(catVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok {
|
||||
if model.IsSyncStatusDelete(catVendorInfo.CatSyncStatus) { //删除
|
||||
if !dao.IsVendorThingIDEmpty(catVendorInfo.VendorCatID) &&
|
||||
model.IsSyncStatusNeedDelete(catVendorInfo.CatSyncStatus) {
|
||||
err = multiStoresHandler.DeleteCategory2(ctx, catVendorInfo.VendorOrgCode, catVendorInfo.VendorCatID)
|
||||
}
|
||||
} else if model.IsSyncStatusNew(catVendorInfo.CatSyncStatus) { // 新增
|
||||
err = multiStoresHandler.CreateCategory2(ctx, catVendorInfo)
|
||||
} else if model.IsSyncStatusUpdate(catVendorInfo.CatSyncStatus) { // 修改
|
||||
err = multiStoresHandler.UpdateCategory2(ctx, catVendorInfo)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("平台:%d不合法", catVendorInfo.VendorID)
|
||||
}
|
||||
if err = OnThingSync(ctx, dao.GetDB(), SkuCategoryVendor2ThingMap(catVendorInfo), err); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
return retVal, err
|
||||
}, catList)
|
||||
tasksch.HandleTask(task, parentTask, len(catList) == 0 || len(catList) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, catIDs []int, isAsync bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SyncCategories vendorIDs:%v, appOrgCodes:%v, catIDs:%v", vendorIDs, appOrgCodes, catIDs)
|
||||
db := dao.GetDB()
|
||||
catList, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true)
|
||||
if err == nil && len(catList) > 0 {
|
||||
// TODO 同一平台不同账号会有影响needSyncParentIDs,暂不处理
|
||||
var needSyncParentIDs []int
|
||||
for _, cat := range catList {
|
||||
if cat.Level == 2 && cat.ParentVendorCatID == "" && cat.IsExdSpec == model.NO {
|
||||
needSyncParentIDs = append(needSyncParentIDs, cat.ParentID)
|
||||
}
|
||||
}
|
||||
if len(needSyncParentIDs) > 0 {
|
||||
task := tasksch.NewSeqTask(fmt.Sprintf("同步分类1:%v", catIDs), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
catList2, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, needSyncParentIDs, true)
|
||||
if err == nil {
|
||||
_, err = syncCategories(ctx, db, task, catList2, false)
|
||||
}
|
||||
case 1:
|
||||
catList2, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true)
|
||||
if err == nil {
|
||||
_, err = syncCategories(ctx, db, task, catList2, false)
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}, 2)
|
||||
tasksch.HandleTask(task, parentTask, len(catIDs) == 0 || len(catIDs) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hint, err = syncCategories(ctx, db, parentTask, catList, false)
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, nameIDs, skuIDs []int, isAsync bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SyncSkus vendorIDs:%v, appOrgCodes:%v, nameIDs:%v, skuIDs:%v", vendorIDs, appOrgCodes, nameIDs, skuIDs)
|
||||
db := dao.GetDB()
|
||||
skuList, err := dao.GetSkusWithVendor(db, vendorIDs, appOrgCodes, nameIDs, skuIDs, true)
|
||||
if err == nil && len(skuList) > 0 {
|
||||
// todo 按vendorID orgCode合并操作
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("同步商品:%v,%v", nameIDs, skuIDs), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
skuVendorInfo := batchItemList[0].(*dao.StoreSkuSyncInfo)
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
if skuVendorInfo.VendorCatID == "" {
|
||||
return nil, fmt.Errorf("商品:%d的商家分类没有同步", skuVendorInfo.SkuID)
|
||||
}
|
||||
if skuVendorInfo.BindID == 0 {
|
||||
return nil, fmt.Errorf("商品:%d的数据异常", skuVendorInfo.SkuID)
|
||||
}
|
||||
if skuVendorInfo.ExdSkuID != "" {
|
||||
return nil, err
|
||||
}
|
||||
if skuVendorInfo.SkuVendorMapCatID != "" {
|
||||
skuVendorInfo.VendorVendorCatID = utils.Str2Int64(skuVendorInfo.SkuVendorMapCatID)
|
||||
}
|
||||
skuVendorInfo.SkuName = jxutils.ComposeSkuNameSync(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0, skuVendorInfo.ExPrefix, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd)
|
||||
skuVendorInfo.SkuNameOrigin = jxutils.ComposeSkuNameOriginal(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0)
|
||||
if skuVendorInfo.ImgWatermark != "" {
|
||||
downLoad, _ := uploadImgStandard(skuVendorInfo.ImgWatermark)
|
||||
skuVendorInfo.ImgMix = jxutils.MixWatermarkImg(downLoad, skuVendorInfo.Img, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd)
|
||||
}
|
||||
skuVendorInfo.MergedStatus = jxutils.MergeSkuStatus(skuVendorInfo.Status, skuVendorInfo.NameStatus)
|
||||
if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(skuVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok {
|
||||
if model.IsSyncStatusDelete(skuVendorInfo.SkuSyncStatus) { //删除
|
||||
if !dao.IsVendorThingIDEmpty(skuVendorInfo.VendorSkuID) &&
|
||||
model.IsSyncStatusNeedDelete(skuVendorInfo.SkuSyncStatus) {
|
||||
err = multiStoresHandler.DeleteSku2(ctx, skuVendorInfo.VendorOrgCode, storeSkuSyncInfo2Bare(skuVendorInfo))
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "删除商品")
|
||||
}
|
||||
}
|
||||
} else if model.IsSyncStatusNew(skuVendorInfo.SkuSyncStatus) { // 新增
|
||||
err = multiStoresHandler.CreateSku2(ctx, skuVendorInfo)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "新增商品")
|
||||
}
|
||||
} else if model.IsSyncStatusUpdate(skuVendorInfo.SkuSyncStatus) { // 修改
|
||||
err = multiStoresHandler.UpdateSku2(ctx, skuVendorInfo)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "修改商品")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("平台:%d不合法", skuVendorInfo.VendorID)
|
||||
}
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
if err = OnThingSync(ctx, dao.GetDB(), SkuVendor2ThingMap(skuVendorInfo), err); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
return retVal, err
|
||||
}, skuList)
|
||||
if isAsync {
|
||||
buildSetFinishHook(task, ctx)
|
||||
}
|
||||
tasksch.HandleTask(task, parentTask, len(skuList) == 0 || len(skuList) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if len(task.GetFailedList()) > 0 {
|
||||
err2 = buildErrMsg(task)
|
||||
err2 = makeSyncError(err2)
|
||||
}
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncReorderCategories(ctx *jxcontext.Context, parentCatID int, isAsync bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SyncReorderCategories parentCatID:%d", parentCatID)
|
||||
db := dao.GetDB()
|
||||
hint, err = CurVendorSync.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("分类重排序:%d", parentCatID), isAsync, false,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorInfo := batchItemList[0].(*MultiStoreVendorInfo)
|
||||
multiStoresHandler := CurVendorSync.GetMultiStoreHandler(vendorInfo.VendorID)
|
||||
if multiStoresHandler != nil {
|
||||
catList, err2 := dao.GetSkuCategoryWithVendor(db, []int{vendorInfo.VendorID}, []string{vendorInfo.OrgCode}, parentCatID, nil, false)
|
||||
if err = err2; err == nil {
|
||||
var vendorCatIDList []string
|
||||
for _, v := range catList {
|
||||
if v.VendorCatID != "" {
|
||||
vendorCatIDList = append(vendorCatIDList, v.VendorCatID)
|
||||
}
|
||||
}
|
||||
if len(vendorCatIDList) > 0 {
|
||||
if err = multiStoresHandler.ReorderCategories2(ctx, vendorInfo.OrgCode, catList[0].ParentVendorCatID, vendorCatIDList); err == nil {
|
||||
retVal = []int{len(vendorCatIDList)}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("非法平台:%d", vendorInfo.VendorID)
|
||||
}
|
||||
return retVal, err
|
||||
})
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func getThingMap(db *dao.DaoDB, thingMap *model.ThingMap) (err error) {
|
||||
return dao.GetEntity(db, thingMap, "ThingID", "ThingType", "VendorID", "VendorOrgCode", model.FieldDeletedAt)
|
||||
}
|
||||
|
||||
func OnCreateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList = getMultiStoreVendorInfoList()
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.OrgCode,
|
||||
SyncStatus: model.SyncFlagNewMask,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(thingMap, ctx.GetUserName())
|
||||
if err2 := dao.CreateEntity(db, thingMap); err2 != nil {
|
||||
if dao.IsDuplicateError(err2) {
|
||||
errList.AddErr(onUpdateThing(ctx, db, vendorInfoList, thingID, thingType, model.SyncFlagNewMask))
|
||||
} else {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
updateThingMapEntity(db, thingMap)
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func onUpdateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8, syncStatus int8) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList = getMultiStoreVendorInfoList()
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.OrgCode,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
if err2 := getThingMap(db, thingMap); err2 == nil {
|
||||
thingMap.SyncStatus |= syncStatus
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
_, err2 = dao.UpdateEntity(db, thingMap)
|
||||
errList.AddErr(err2)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
} else {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func OnUpdateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8) (err error) {
|
||||
return onUpdateThing(ctx, db, vendorInfoList, thingID, thingType, model.SyncFlagModifiedMask)
|
||||
}
|
||||
|
||||
func OnDeleteThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList = getMultiStoreVendorInfoList()
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.OrgCode,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
if err2 := getThingMap(db, thingMap); err2 == nil {
|
||||
if model.IsSyncStatusNew(thingMap.SyncStatus) {
|
||||
thingMap.SyncStatus = 0
|
||||
thingMap.DeletedAt = time.Now()
|
||||
} else {
|
||||
thingMap.SyncStatus |= model.SyncFlagDeletedMask
|
||||
}
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
_, err2 = dao.UpdateEntity(db, thingMap)
|
||||
errList.AddErr(err2)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
} else if !dao.IsNoRowsError(err2) {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func SkuCategoryVendor2ThingMap(cat *dao.SkuStoreCatInfo) (thingMap *model.ThingMap) {
|
||||
thingMap = &model.ThingMap{
|
||||
ThingID: int64(cat.ID),
|
||||
ThingType: model.ThingTypeCategory,
|
||||
VendorID: cat.VendorID,
|
||||
VendorOrgCode: cat.VendorOrgCode,
|
||||
|
||||
SyncStatus: cat.CatSyncStatus,
|
||||
VendorThingID: cat.VendorCatID,
|
||||
}
|
||||
thingMap.ID = cat.MapID // 一定要赋值
|
||||
return thingMap
|
||||
}
|
||||
|
||||
func SkuVendor2ThingMap(sku *dao.StoreSkuSyncInfo) (thingMap *model.ThingMap) {
|
||||
thingMap = &model.ThingMap{
|
||||
ThingID: int64(sku.SkuID),
|
||||
ThingType: model.ThingTypeSku,
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrgCode: sku.VendorOrgCode,
|
||||
|
||||
SyncStatus: sku.SkuSyncStatus,
|
||||
VendorThingID: sku.VendorSkuID,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
thingMap.ID = sku.BindID // 一定要赋值
|
||||
return thingMap
|
||||
}
|
||||
|
||||
func OnThingSync(ctx *jxcontext.Context, db *dao.DaoDB, thingMap *model.ThingMap, syncErr error) (err error) {
|
||||
globals.SugarLogger.Debugf("OnThingSync thingMap:%s", utils.Format4Output(thingMap, true))
|
||||
if syncErr != nil {
|
||||
err = syncErr
|
||||
thingMap.Remark = utils.LimitUTF8StringLen(err.Error(), 255)
|
||||
dao.UpdateEntity(db, thingMap, "Remark")
|
||||
} else {
|
||||
updateFields := []string{
|
||||
model.FieldSyncStatus,
|
||||
model.FieldUpdatedAt,
|
||||
model.FieldLastOperator,
|
||||
"Remark",
|
||||
}
|
||||
if model.IsSyncStatusDelete(thingMap.SyncStatus) { //删除
|
||||
thingMap.DeletedAt = time.Now()
|
||||
thingMap.VendorThingID = ""
|
||||
updateFields = append(updateFields, "VendorThingID", model.FieldDeletedAt)
|
||||
} else if model.IsSyncStatusNew(thingMap.SyncStatus) { // 新增
|
||||
updateFields = append(updateFields, "VendorThingID")
|
||||
}
|
||||
thingMap.SyncStatus = 0
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
thingMap.UpdatedAt = time.Now()
|
||||
thingMap.Remark = ""
|
||||
_, err = dao.UpdateEntity(db, thingMap, updateFields...)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func updateThingMapEntity(db *dao.DaoDB, thingMap *model.ThingMap) {
|
||||
// if thingMap.VendorOrgCode == globals.JdOrgCode {
|
||||
// if thingMap.ThingType == model.ThingTypeCategory {
|
||||
// cat := &model.SkuCategory{
|
||||
// JdID: utils.Str2Int64WithDefault(thingMap.VendorThingID, 0),
|
||||
// JdSyncStatus: thingMap.SyncStatus,
|
||||
// }
|
||||
// cat.ID = int(thingMap.ThingID)
|
||||
// dao.UpdateEntity(db, cat, "JdID", "JdSyncStatus")
|
||||
// } else if thingMap.ThingType == model.ThingTypeSku {
|
||||
// sku := &model.Sku{
|
||||
// JdID: utils.Str2Int64WithDefault(thingMap.VendorThingID, 0),
|
||||
// JdSyncStatus: thingMap.SyncStatus,
|
||||
// }
|
||||
// sku.ID = int(thingMap.ThingID)
|
||||
// dao.UpdateEntity(db, sku, "JdID", "JdSyncStatus")
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
func amendAndPruneVendorStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID int, vendorOrgCode string, isAsync, isContinueWhenError bool, opType int, isForceUpdate bool) (hint string, err error) {
|
||||
handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
|
||||
if handler == nil {
|
||||
return "", fmt.Errorf("平台:%s不支持此操作", model.VendorChineseNames[vendorID])
|
||||
}
|
||||
db := dao.GetDB()
|
||||
vendorInfo := []*MultiStoreVendorInfo{
|
||||
&MultiStoreVendorInfo{
|
||||
VendorID: vendorID,
|
||||
OrgCode: vendorOrgCode,
|
||||
},
|
||||
}
|
||||
var sku2Delete []*partner.StoreSkuInfo
|
||||
var cat2Delete []*partner.BareCategoryInfo
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("平台:%s,账号:%s上的商品与商家分类", model.VendorChineseNames[vendorID], vendorOrgCode),
|
||||
tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
localSkuList, err := dao.GetSkusWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localSkuMap := make(map[string]*dao.StoreSkuSyncInfo)
|
||||
for _, v := range localSkuList {
|
||||
if v.VendorSkuID != "" {
|
||||
localSkuMap[v.VendorSkuID] = v
|
||||
}
|
||||
}
|
||||
|
||||
remoteSkuList, err2 := handler.GetSkus(ctx, vendorOrgCode, 0, "")
|
||||
if err = err2; err == nil {
|
||||
remoteSkuMap := make(map[string]int)
|
||||
for _, v := range remoteSkuList {
|
||||
if vendorSkuID := v.SkuList[0].VendorSkuID; vendorSkuID != "" {
|
||||
if localSkuMap[vendorSkuID] == nil {
|
||||
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
|
||||
SkuID: v.SkuList[0].SkuID,
|
||||
VendorSkuID: vendorSkuID,
|
||||
})
|
||||
} else {
|
||||
remoteSkuMap[vendorSkuID] = 1
|
||||
}
|
||||
} else if v.VendorNameID != "" {
|
||||
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
|
||||
SkuID: v.NameID,
|
||||
VendorSkuID: v.VendorNameID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if opType == AmendPruneOnlyAmend || opType == AmendPruneAll {
|
||||
for _, v := range localSkuList {
|
||||
if v.ExdSkuID == "" {
|
||||
if v.BindID != 0 {
|
||||
if !model.IsSyncStatusDelete(v.SkuSyncStatus) {
|
||||
if remoteSkuMap[v.VendorSkuID] == 0 {
|
||||
if !model.IsSyncStatusNew(v.SkuSyncStatus) {
|
||||
OnCreateThing(ctx, db, vendorInfo, int64(v.SkuID), model.ThingTypeSku)
|
||||
}
|
||||
} else if isForceUpdate {
|
||||
OnUpdateThing(ctx, db, vendorInfo, int64(v.SkuID), model.ThingTypeSku)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OnCreateThing(ctx, db, vendorInfo, int64(v.SkuID), model.ThingTypeSku)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(sku2Delete) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo("删除商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
if err = handler.DeleteSku2(ctx, vendorOrgCode, batchedStoreSkuList[0]); err == nil {
|
||||
successCount = 1
|
||||
}
|
||||
return nil, successCount, err
|
||||
}, ctx, task, sku2Delete, 1, isContinueWhenError)
|
||||
}
|
||||
sku2Delete = nil
|
||||
case 2:
|
||||
localCatList, err := dao.GetSkuCategoryWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, -1, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localCatMap := make(map[string]*dao.SkuStoreCatInfo)
|
||||
for _, v := range localCatList {
|
||||
localCatMap[v.VendorCatID] = v
|
||||
localCatMap[v.Name] = v
|
||||
localCatMap[utils.Int2Str(v.ID)] = v
|
||||
}
|
||||
|
||||
remoteCatList, err2 := handler.GetAllCategories(ctx, vendorOrgCode)
|
||||
if err = err2; err == nil {
|
||||
remoteCatMap := make(map[string]int)
|
||||
cat2Delete = checkRemoteCatExist(remoteCatMap, localCatMap, remoteCatList)
|
||||
|
||||
for _, v := range localCatList {
|
||||
if v.IsExdSpec == model.NO {
|
||||
if v.MapID != 0 {
|
||||
if !model.IsSyncStatusDelete(v.CatSyncStatus) {
|
||||
if remoteCatMap[v.VendorCatID] == 0 {
|
||||
if !model.IsSyncStatusNew(v.CatSyncStatus) {
|
||||
OnCreateThing(ctx, db, vendorInfo, int64(v.ID), model.ThingTypeCategory)
|
||||
}
|
||||
} else if isForceUpdate && !model.IsSyncStatusUpdate(v.CatSyncStatus) {
|
||||
OnUpdateThing(ctx, db, vendorInfo, int64(v.ID), model.ThingTypeCategory)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OnCreateThing(ctx, db, vendorInfo, int64(v.ID), model.ThingTypeCategory)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(cat2Delete) > 0 {
|
||||
for i := 0; i < 2; i++ {
|
||||
level := 2 - i
|
||||
var levelCat2Delete []*partner.BareCategoryInfo
|
||||
for _, v := range cat2Delete {
|
||||
if v.Level == level {
|
||||
levelCat2Delete = append(levelCat2Delete, v)
|
||||
}
|
||||
}
|
||||
if len(levelCat2Delete) > 0 {
|
||||
task4Delete := tasksch.NewParallelTask(fmt.Sprintf("删除商家分类,level:%d", level), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
cat := batchItemList[0].(*partner.BareCategoryInfo)
|
||||
err = handler.DeleteCategory2(ctx, vendorOrgCode, cat.VendorCatID)
|
||||
return nil, err
|
||||
}, levelCat2Delete)
|
||||
tasksch.HandleTask(task4Delete, task, true).Run()
|
||||
_, err = task4Delete.GetResult(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
cat2Delete = nil
|
||||
}
|
||||
return nil, err
|
||||
}, []int{0, 1, 2, 3})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
hint = "1"
|
||||
} else {
|
||||
hint = task.ID
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func FullSyncVendorStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID int, vendorOrgCode string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
multiStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
|
||||
if multiStoreHandler == nil {
|
||||
return "", fmt.Errorf("vendorID:%d不是多门店平台", vendorID)
|
||||
}
|
||||
task := tasksch.NewParallelTask("FullSyncStoreSkuNew", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(false), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
_, err = amendAndPruneVendorStuff(ctx, task, vendorID, vendorOrgCode, false, isContinueWhenError, AmendPruneAll, false)
|
||||
case 1:
|
||||
_, err = SyncCategories(ctx, task, []int{vendorID}, []string{vendorOrgCode}, nil, false)
|
||||
case 2:
|
||||
_, err = SyncSkus(ctx, task, []int{vendorID}, []string{vendorOrgCode}, nil, nil, false)
|
||||
}
|
||||
return retVal, err
|
||||
}, []int{0, 1, 2})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
)
|
||||
|
||||
// 如果京西门为打开,打开状态为非营业的平台门店
|
||||
func OpenRemoteStoreByJxStatus(ctx *jxcontext.Context, vendorIDs, storeIDs []int, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
status := model.StoreStatusAll
|
||||
if !isForce {
|
||||
status = model.StoreStatusClosed
|
||||
}
|
||||
storeMapList, err := dao.GetStoresMapList(db, vendorIDs, storeIDs, nil, status, model.StoreIsSyncYes, "", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
vendorIDMap := make(map[int]int)
|
||||
if len(vendorIDs) == 0 {
|
||||
for k := range partner.PurchasePlatformHandlers {
|
||||
vendorIDMap[k] = 1
|
||||
}
|
||||
} else {
|
||||
for _, v := range vendorIDs {
|
||||
vendorIDMap[v] = 1
|
||||
}
|
||||
}
|
||||
task := tasksch.NewParallelTask("OpenRemoteStoreByJxStatus", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
if handler, _ := partner.GetPurchasePlatformFromVendorID(storeMap.VendorID).(partner.IStoreHandler); handler != nil {
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeMap.StoreID, storeMap.VendorID)
|
||||
if err == nil && storeDetail.Status == model.StoreStatusOpened {
|
||||
if err = handler.UpdateStoreStatus(ctx, storeMap.VendorOrgCode, storeMap.StoreID, storeMap.VendorStoreID, model.StoreStatusOpened); err == nil {
|
||||
storeMap.Status = model.StoreStatusOpened
|
||||
dao.UpdateEntity(db, storeMap, model.FieldStatus)
|
||||
retVal = []int{1}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, storeMapList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,329 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
|
||||
"github.com/360EntSecGroup-Skylar/excelize"
|
||||
)
|
||||
|
||||
func storeOrSkuMap2List(intStrMap map[int]string) (ids []int) {
|
||||
for k, v := range intStrMap {
|
||||
if v != "" {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func getStoreSkus(db *dao.DaoDB, storeID int, skuIDs []int) (skus []*dao.StoreSkuSyncInfo, err error) {
|
||||
sql := `
|
||||
SELECT
|
||||
t1.id bind_id, t1.sku_id, t1.price, t1.unit_price, t1.status store_sku_status,
|
||||
t1.jd_sync_status sku_sync_status, t1.jd_price vendor_price, t1.jd_lock_time lock_time,
|
||||
t1.store_id, t1.deleted_at bind_deleted_at,t1.status_sale_begin,t1.status_sale_end,
|
||||
t2.*,
|
||||
t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, t3.status name_status, t3.ex_prefix, t3.ex_prefix_begin, t3.ex_prefix_end
|
||||
FROM store_sku_bind t1
|
||||
LEFT JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ?/* AND t2.status = ?*/
|
||||
LEFT JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ?/* AND t3.status = ?*/
|
||||
WHERE 1 = 1
|
||||
AND t1.store_id = ?
|
||||
AND t1.deleted_at = ?
|
||||
AND t1.sku_id IN ( ` + dao.GenQuestionMarks(len(skuIDs)) + `)
|
||||
ORDER BY t1.price`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
storeID,
|
||||
utils.DefaultTimeValue,
|
||||
skuIDs,
|
||||
}
|
||||
if err = dao.GetRows(db, &skus, sql, sqlParams...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return skus, err
|
||||
}
|
||||
|
||||
func SyncStoreSku4FakeJD(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inSkuMap map[int]string, isContinueWhenError bool) (err error) {
|
||||
vendorID := model.VendorIDJD
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storeDetail.VendorOrgCode = apimanager.FakeJdOrgCode
|
||||
skuIDs := storeOrSkuMap2List(inSkuMap)
|
||||
skus, err := getStoreSkus(db, storeID, skuIDs)
|
||||
if err != nil || len(skus) == 0 {
|
||||
return err
|
||||
}
|
||||
formalizeStoreSkuList(skus)
|
||||
storeSkuHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
|
||||
|
||||
var (
|
||||
stockList, onlineList, offlineList, priceList []*partner.StoreSkuInfo
|
||||
)
|
||||
skuMap := make(map[*partner.StoreSkuInfo]*dao.StoreSkuSyncInfo)
|
||||
now := jxutils.OperationTime2HourMinuteFormat(time.Now())
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
for _, sku := range skus {
|
||||
sku.SkuSyncStatus = model.SyncFlagSaleMask | model.SyncFlagPriceMask | model.SyncFlagStockMask
|
||||
sku.VendorSkuID = inSkuMap[sku.SkuID]
|
||||
sku.SkuID = int(utils.Str2Int64(sku.VendorSkuID)) // skuID与vendorID一样
|
||||
sku.VendorOrgCode = apimanager.FakeJdOrgCode
|
||||
|
||||
sku.VendorPrice = 0
|
||||
sku.MergedStatus = MergeSkuSaleStatusWithStoreOpTime(sku, storeDetail, now)
|
||||
var bareSku *partner.StoreSkuInfo
|
||||
if isStoreSkuSyncNeedDelete(sku) {
|
||||
if !dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
stockList = append(stockList, bareSku)
|
||||
} else {
|
||||
// updateItems = append(updateItems, sku2Update(vendorID, sku, model.SyncFlagDeletedMask))
|
||||
}
|
||||
} else if model.IsSyncStatusNew(sku.SkuSyncStatus) {
|
||||
calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage))
|
||||
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
// todo 多平台商品库没有正常创建,直接跳过
|
||||
} else {
|
||||
sku.SkuSyncStatus |= model.SyncFlagSaleMask | model.SyncFlagPriceMask
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
stockList = append(stockList, bareSku)
|
||||
priceList = append(priceList, bareSku)
|
||||
if sku.MergedStatus == model.SkuStatusNormal {
|
||||
onlineList = append(onlineList, bareSku)
|
||||
} else {
|
||||
offlineList = append(offlineList, bareSku)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
// err = fmt.Errorf("门店:%d,修改没有创建的商品:%d", storeID, sku.SkuID)
|
||||
err = utils.NewErrorCode(fmt.Sprintf("门店:%d,修改没有创建的商品:%d", storeID, sku.SkuID), "-1", 0)
|
||||
failedList = putils.GetErrMsg2FailedSingleList(nil, err, storeID, model.VendorChineseNames[vendorID], "异常同步错误")
|
||||
if parentTask == nil {
|
||||
return err
|
||||
}
|
||||
parentTask.AddBatchErr(err)
|
||||
parentTask.AddFailedList(failedList)
|
||||
} else {
|
||||
isAdded2Update := false
|
||||
if model.IsSyncStatusPrice(sku.SkuSyncStatus) {
|
||||
bareSku = storeSkuSyncInfo2Bare(calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage)))
|
||||
priceList = append(priceList, bareSku)
|
||||
}
|
||||
if !isAdded2Update {
|
||||
if model.IsSyncStatusSale(sku.SkuSyncStatus) {
|
||||
if bareSku == nil {
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
}
|
||||
if sku.MergedStatus == model.SkuStatusNormal {
|
||||
onlineList = append(onlineList, bareSku)
|
||||
stockList = append(stockList, bareSku)
|
||||
} else {
|
||||
offlineList = append(offlineList, bareSku)
|
||||
// 因为京东平台以是否有库存表示是否关注,所以不论是否可售,都要设置库存
|
||||
stockList = append(stockList, bareSku)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if bareSku != nil {
|
||||
skuMap[bareSku] = sku
|
||||
}
|
||||
}
|
||||
bareSku2Sync := func(bareSkuList []*partner.StoreSkuInfo) (skuList []*dao.StoreSkuSyncInfo) {
|
||||
if len(bareSkuList) > 0 {
|
||||
skuList = make([]*dao.StoreSkuSyncInfo, len(bareSkuList))
|
||||
for k, v := range bareSkuList {
|
||||
skuList[k] = skuMap[v]
|
||||
}
|
||||
}
|
||||
return skuList
|
||||
}
|
||||
isContinueWhenError2 := true
|
||||
realStoreID := int(utils.Str2Int64(vendorStoreID))
|
||||
task := tasksch.NewParallelTask("SyncStoreSku4FakeJD", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError2), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
// globals.SugarLogger.Debugf("step:%d", step)
|
||||
switch step {
|
||||
case 0:
|
||||
for k, list := range [][]*partner.StoreSkuInfo{stockList /*, onlineList*/} {
|
||||
if len(list) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品库存", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusStock(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if k == 0 && len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagStockMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, list, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStock), isContinueWhenError2)
|
||||
}
|
||||
}
|
||||
case 1, 2:
|
||||
statusList := onlineList
|
||||
status := model.SkuStatusNormal
|
||||
name := "可售门店商品"
|
||||
if step == 2 {
|
||||
statusList = offlineList
|
||||
status = model.SkuStatusDontSale
|
||||
name = "不可售门店商品"
|
||||
}
|
||||
if len(statusList) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo(name, func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusStatus(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList, status)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagSaleMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, statusList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStatus), isContinueWhenError2)
|
||||
}
|
||||
case 3:
|
||||
if len(priceList) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品价格", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusPrice(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagPriceMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, priceList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusPrice), isContinueWhenError2)
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, []int{0, 1, 2, 3})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
return err
|
||||
}
|
||||
|
||||
func SyncFakeJdStoreSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeMap, skuMap map[int]string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
storeIDs := storeOrSkuMap2List(storeMap)
|
||||
task := tasksch.NewParallelTask("同步假京东", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeID := batchItemList[0].(int)
|
||||
err = SyncStoreSku4FakeJD(ctx, task, storeID, storeMap[storeID], skuMap, isContinueWhenError)
|
||||
return retVal, err
|
||||
}, storeIDs)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
_, err = task.GetResult(0)
|
||||
hint = utils.Int2Str(len(storeIDs))
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func excel2FakeJdThingMap(ctx *jxcontext.Context, reader io.Reader) (thingMapList []*model.FakeJdThingMap, err error) {
|
||||
xlsx, err := excelize.OpenReader(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for sheetIndex := 0; sheetIndex < xlsx.SheetCount; sheetIndex++ {
|
||||
rows, err2 := xlsx.GetRows(xlsx.GetSheetName(sheetIndex + 1))
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
for rowNum, row := range rows {
|
||||
thingMap := &model.FakeJdThingMap{
|
||||
JxID: int(utils.Str2Int64WithDefault(row[0], 0)),
|
||||
JdID: utils.Str2Int64WithDefault(row[1], 0),
|
||||
}
|
||||
if thingMap.JxID == 0 || thingMap.JdID == 0 {
|
||||
if rowNum == 0 {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if sheetIndex == 0 {
|
||||
thingMap.ThingType = model.ThingTypeStore
|
||||
} else {
|
||||
thingMap.ThingType = model.ThingTypeSku
|
||||
}
|
||||
dao.WrapAddIDCULEntity(thingMap, ctx.GetUserName())
|
||||
thingMapList = append(thingMapList, thingMap)
|
||||
}
|
||||
}
|
||||
return thingMapList, err
|
||||
}
|
||||
|
||||
func getFakeThingMap(ctx *jxcontext.Context, db *dao.DaoDB) (storeMap, skuMap map[int]string, err error) {
|
||||
var thingMapList []*model.FakeJdThingMap
|
||||
err = dao.GetRows(db, &thingMapList, "SELECT t1.* FROM fake_jd_thing_map t1")
|
||||
if err == nil {
|
||||
storeMap, skuMap = make(map[int]string), make(map[int]string)
|
||||
for _, v := range thingMapList {
|
||||
if v.ThingType == model.ThingTypeStore {
|
||||
storeMap[v.JxID] = utils.Int64ToStr(v.JdID)
|
||||
} else {
|
||||
skuMap[v.JxID] = utils.Int64ToStr(v.JdID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return storeMap, skuMap, err
|
||||
}
|
||||
|
||||
func UploadFakeJdThingMap(ctx *jxcontext.Context, reader io.Reader, isSyncNow, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
thingMapList, err := excel2FakeJdThingMap(ctx, reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
_, err = dao.ExecuteSQL(db, "DELETE t1 FROM fake_jd_thing_map t1")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return "", err
|
||||
}
|
||||
err = dao.CreateMultiEntities(db, thingMapList)
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return "", err
|
||||
}
|
||||
dao.Commit(db)
|
||||
|
||||
if isSyncNow {
|
||||
if storeMap, skuMap, err2 := getFakeThingMap(ctx, db); err2 == nil {
|
||||
hint, err = SyncFakeJdStoreSku(ctx, nil, storeMap, skuMap, isAsync, isContinueWhenError)
|
||||
}
|
||||
} else {
|
||||
hint = utils.Int2Str(len(thingMapList))
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
func TestSyncStoreSku4FakeJD(t *testing.T) {
|
||||
skuMap := map[int]string{
|
||||
22509: "2029937911",
|
||||
}
|
||||
err := SyncStoreSku4FakeJD(jxcontext.AdminCtx, nil, 100118, "11943257", skuMap, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadFakeJdThingMap(t *testing.T) {
|
||||
file, err := os.Open("到家菜市门店与商品映射信息(1).xlsx")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hint, err := UploadFakeJdThingMap(jxcontext.AdminCtx, file, true, false, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(hint)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
)
|
||||
|
||||
func TestFreeBatchStoreSkuInfo(t *testing.T) {
|
||||
var sku2Delete []*partner.StoreSkuInfo
|
||||
for i := 0; i < 123; i++ {
|
||||
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
|
||||
SkuID: i + 1,
|
||||
})
|
||||
}
|
||||
|
||||
ctx := jxcontext.AdminCtx
|
||||
var parentTask tasksch.ITask
|
||||
isContinueWhenError := true
|
||||
handler, _ := partner.GetPurchasePlatformFromVendorID(model.VendorIDEBAI).(partner.ISingleStoreStoreSkuHandler)
|
||||
_, err := putils.FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
t.Log(len(batchedStoreSkuList))
|
||||
return nil, 0, err
|
||||
}, ctx, parentTask, sku2Delete, handler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus), isContinueWhenError)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTimeMixByInt(t *testing.T) {
|
||||
const (
|
||||
time1 = 1100
|
||||
time2 = 2300
|
||||
time3 = 1200
|
||||
time4 = 2400
|
||||
)
|
||||
a, b := GetTimeMixByInt(time1, time2, time3, time4)
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
package cms
|
||||
|
||||
// var (
|
||||
// LoginTypeFieldMap = map[string]string{
|
||||
// mobile.LoginType: "tel",
|
||||
// weixin.LoginType: "openid",
|
||||
// weixin.LoginTypeMiniProgram: "openid_mini",
|
||||
// }
|
||||
// )
|
||||
|
||||
// func GetStoreUsers(ctx *jxcontext.Context, storeID int) (storeUserInfos []*dao.StoreUserInfo, err error) {
|
||||
// sql := `
|
||||
// SELECT t1.id, t1.jxstoreid, t1.openid, t1.tel, t1.nickname, t1.parentid, t3.tel parent_mobile,
|
||||
// CONCAT("[", GROUP_CONCAT(CONCAT('{"id":', t2.id, ',"parentID":', t2.parentid, ',"tel":"', t2.tel, '","nickname":"', IF(t2.nickname IS NULL, "", t2.nickname), '"}')), "]") members_str
|
||||
// FROM weixins t1
|
||||
// LEFT JOIN weixins t2 ON t2.parentid = t1.id
|
||||
// LEFT JOIN weixins t3 ON t1.parentid = t3.id
|
||||
// WHERE t1.parentid = -1 AND t1.jxstoreid = ?
|
||||
// GROUP BY 1,2,3,4,5,6,7;
|
||||
// `
|
||||
// // globals.SugarLogger.Debug(sql)
|
||||
// if err = dao.GetRows(nil, &storeUserInfos, sql, storeID); err == nil {
|
||||
// for _, storeUserInfo := range storeUserInfos {
|
||||
// if storeUserInfo.MembersStr != "" {
|
||||
// err = utils.UnmarshalUseNumber([]byte(storeUserInfo.MembersStr), &storeUserInfo.Members)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return storeUserInfos, err
|
||||
// }
|
||||
|
||||
// func GetUserInfo(ctx *jxcontext.Context, mobile string) (storeUserInfo *dao.StoreUserInfo, err error) {
|
||||
// storeUserInfo, err = dao.GetUserStoreInfo(dao.GetDB(), "tel", mobile)
|
||||
// globals.SugarLogger.Debugf("GetUserInfo:%s, token:%s, mobile:%s, storeUserInfo:%s, err:%v", ctx.GetTrackInfo(), ctx.GetToken(), mobile, utils.Format4Output(storeUserInfo, true), err)
|
||||
// return storeUserInfo, err
|
||||
// }
|
||||
|
||||
// func GetSelfInfo(ctx *jxcontext.Context) (storeUserInfo *dao.StoreUserInfo, err error) {
|
||||
// loginInfo := ctx.GetLoginInfo()
|
||||
// if loginInfo == nil {
|
||||
// return nil, auth.ErrAPINeedRealLogin
|
||||
// }
|
||||
// fieldName := LoginTypeFieldMap[loginInfo.GetAuthType()]
|
||||
// if fieldName == "" {
|
||||
// return nil, auth.ErrIllegalLoginType
|
||||
// }
|
||||
// storeUserInfo, err = dao.GetUserStoreInfo(dao.GetDB(), fieldName, loginInfo.GetAuthID())
|
||||
// globals.SugarLogger.Debugf("GetSelfInfo:%s, token:%s, storeUserInfo:%s, err:%v", ctx.GetTrackInfo(), ctx.GetToken(), utils.Format4Output(storeUserInfo, true), err)
|
||||
// return storeUserInfo, err
|
||||
// }
|
||||
|
||||
// func GetMyStoreList(ctx *jxcontext.Context) (storeList []*dao.StoreWithCityName, err error) {
|
||||
// mobileNum, _ := ctx.GetMobileAndUserID()
|
||||
// if mobileNum == "" {
|
||||
// return nil, fmt.Errorf("不能得到用户手机号")
|
||||
// }
|
||||
// storeList, err = dao.GetStoreListByMobile(dao.GetDB(), mobileNum)
|
||||
// return storeList, err
|
||||
// }
|
||||
|
||||
// func UnbindMobile(ctx *jxcontext.Context, mobile string) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// num, err = dao.UpdateEntityByKV(db, &legacymodel.WeiXins{}, map[string]interface{}{
|
||||
// "JxStoreID": 0,
|
||||
// "ParentID": -1,
|
||||
// }, map[string]interface{}{
|
||||
// "Tel": mobile,
|
||||
// })
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func BindMobile2Store(ctx *jxcontext.Context, mobile string, storeID int) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// user, err2 := verifyMobileIsBlank(db, mobile)
|
||||
// if err = err2; err == nil || err == orm.ErrNoRows {
|
||||
// user.JxStoreID = storeID
|
||||
// if err == nil {
|
||||
// dao.Begin(db)
|
||||
// defer func() {
|
||||
// if r := recover(); r != nil {
|
||||
// dao.Rollback(db)
|
||||
// panic(r)
|
||||
// }
|
||||
// }()
|
||||
// if num, err = dao.UpdateEntity(db, user, "JxStoreID"); err == nil {
|
||||
// err = dao.SetWeiXinsEmpty2Null(db, user)
|
||||
// }
|
||||
// if err != nil {
|
||||
// dao.Rollback(db)
|
||||
// } else {
|
||||
// dao.Commit(db)
|
||||
// }
|
||||
// } else {
|
||||
// // globals.SugarLogger.Debug(utils.Format4Output(user, false))
|
||||
// dao.WrapAddIDCULEntity(user, ctx.GetUserName())
|
||||
// user.ParentID = -1
|
||||
// if err = dao.CreateWeiXins(db, user); err == nil {
|
||||
// num = 1
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func AddMobile2Mobile(ctx *jxcontext.Context, parentMobile, mobile string) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// parentUser := &legacymodel.WeiXins{}
|
||||
// parentUser.Tel = parentMobile
|
||||
// if err = dao.GetEntity(db, parentUser, "Tel"); err == nil {
|
||||
// if parentUser.ParentID == -1 {
|
||||
// globals.SugarLogger.Debug(parentUser)
|
||||
// if err = verifyMobileHasNoMembers(db, mobile); err == nil {
|
||||
// user, err2 := verifyMobileIsBlank(db, mobile)
|
||||
// if err = err2; err == nil || err == orm.ErrNoRows {
|
||||
// user.ParentID = parentUser.ID
|
||||
// if err == nil {
|
||||
// // todo transaction
|
||||
// if num, err = dao.UpdateEntity(db, user, "ParentID"); err == nil {
|
||||
// err = dao.SetWeiXinsEmpty2Null(db, user)
|
||||
// }
|
||||
// } else {
|
||||
// dao.WrapAddIDCULEntity(user, ctx.GetUserName())
|
||||
// if err = dao.CreateWeiXins(db, user); err == nil {
|
||||
// num = 1
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// err = fmt.Errorf("%s本身是成员", parentMobile)
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func ChangeMobile(ctx *jxcontext.Context, curMobile, expectedMobile string) (num int64, err error) {
|
||||
// num, err = dao.UpdateEntityByKV(nil, &legacymodel.WeiXins{}, map[string]interface{}{
|
||||
// "Tel": expectedMobile,
|
||||
// }, map[string]interface{}{
|
||||
// "Tel": curMobile,
|
||||
// })
|
||||
// if err == nil {
|
||||
// TransferLegacyWeixins(curMobile)
|
||||
// TransferLegacyWeixins(expectedMobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func verifyMobileIsBlank(db *dao.DaoDB, mobile string) (user *legacymodel.WeiXins, err error) {
|
||||
// if !jxutils.IsStringLikeMobile(mobile) {
|
||||
// return nil, fmt.Errorf("%s看起来不像是一个手机号", mobile)
|
||||
// }
|
||||
// user = &legacymodel.WeiXins{
|
||||
// Tel: mobile,
|
||||
// }
|
||||
// if err = dao.GetEntity(db, user, "Tel"); err == nil {
|
||||
// if user.ParentID != -1 && user.ParentID != 0 {
|
||||
// userParent := &legacymodel.WeiXins{
|
||||
// ID: user.ParentID,
|
||||
// }
|
||||
// if err = dao.GetEntity(db, userParent); err != nil && err != orm.ErrNoRows {
|
||||
// return nil, err
|
||||
// }
|
||||
// if err != orm.ErrNoRows {
|
||||
// err = fmt.Errorf("%s已经是组长:%s,门店:%d的小组成员", mobile, userParent.Tel, userParent.JxStoreID)
|
||||
// } else {
|
||||
// err = nil
|
||||
// }
|
||||
// } else if user.JxStoreID != 0 {
|
||||
// store := &model.Store{}
|
||||
// store.ID = user.JxStoreID
|
||||
// if err = dao.GetEntity(db, store); err == nil {
|
||||
// err = fmt.Errorf("%s本身已经是门店:%d的组长", mobile, user.JxStoreID)
|
||||
// } else if dao.IsNoRowsError(err) {
|
||||
// err = nil
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return user, err
|
||||
// }
|
||||
|
||||
// func verifyMobileHasNoMembers(db *dao.DaoDB, mobile string) (err error) {
|
||||
// countInfo := &struct{ Ct int }{}
|
||||
// if err = dao.GetRow(db, countInfo, `
|
||||
// SELECT COUNT(*) ct
|
||||
// FROM weixins t1
|
||||
// JOIN weixins t2 ON t1.parentid = t2.id AND t2.tel = ?
|
||||
// `, mobile); err == nil {
|
||||
// if countInfo.Ct > 0 {
|
||||
// user := &legacymodel.WeiXins{
|
||||
// Tel: mobile,
|
||||
// }
|
||||
// dao.GetEntity(db, user, "Tel")
|
||||
// err = fmt.Errorf("%s本身已经是门店:%d组长", mobile, user.JxStoreID)
|
||||
// }
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/globals/api/apimanager"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func TestTryAddStoreBossRole4User(t *testing.T) {
|
||||
err := TryAddStoreBossRole4User(jxcontext.AdminCtx, &model.User{
|
||||
Type: model.UserTypeStoreBoss,
|
||||
UserID: "24058800CD3711E991B2525400E86DC0",
|
||||
Mobile: utils.String2Pointer("91112345678"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
var (
|
||||
unitNamesMap map[string]int
|
||||
specUnitNamesMap map[string]int
|
||||
validate = validator.New()
|
||||
)
|
||||
|
||||
func init() {
|
||||
unitNamesMap = jxutils.MakeValidationMapFromSlice(model.UnitNames, 1)
|
||||
specUnitNamesMap = jxutils.MakeValidationMapFromSlice(model.SpecUnitNames, 1)
|
||||
}
|
||||
|
||||
func validateStringInMap(name string, value interface{}, flagMap map[string]int) (err error) {
|
||||
if strValue, ok := value.(string); ok {
|
||||
if flagMap[strValue] == 1 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("属性%s类型或取值不合法,要求string", name)
|
||||
}
|
||||
|
||||
func ValidateUnit(value interface{}) (err error) {
|
||||
return validateStringInMap("Unit", value, unitNamesMap)
|
||||
}
|
||||
|
||||
func ValidateSpecUnit(value interface{}) (err error) {
|
||||
return validateStringInMap("SpecUnit", value, specUnitNamesMap)
|
||||
}
|
||||
|
||||
func ValidateStruct(value interface{}) (err error) {
|
||||
return validate.Struct(value)
|
||||
}
|
||||
|
||||
func ValidateVar(value interface{}, tag string) (err error) {
|
||||
return validate.Var(value, tag)
|
||||
}
|
||||
|
||||
func ValidateStructPartial(value interface{}, fields ...string) (err error) {
|
||||
return validate.StructPartial(value, fields...)
|
||||
}
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,33 +1,29 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
var (
|
||||
NoUseEventMap = map[string]string{
|
||||
"CreateQrOrBarCode": "CreateQrOrBarCode",
|
||||
"StatisticsReportForOrders": "StatisticsReportForOrders",
|
||||
"UpdateUser": "UpdateUser",
|
||||
}
|
||||
regexpToken = regexp.MustCompile(`,"token":".*"`)
|
||||
)
|
||||
|
||||
type CheckCookie struct {
|
||||
VendorID int `json:"vendorID"`
|
||||
VendorOrgCode string `json:"vendorOrgCode"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
const (
|
||||
sysMessageTitle = ""
|
||||
)
|
||||
|
||||
func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCode, errMsg string, useTime int, apiFunctionSpec string) (err error) {
|
||||
var (
|
||||
@@ -67,45 +63,45 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
|
||||
ErrMsg: errMsg,
|
||||
UseTime: useTime,
|
||||
}
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
err = dao.CreateEntity(db, event)
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func AddOperateEventDetail(db *dao.DaoDB, operateEventDetail *model.OperateEventDetail) (err error) {
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
operateEventDetail.BeforeData = utils.LimitUTF8StringLen(operateEventDetail.BeforeData, 3200)
|
||||
operateEventDetail.AfterData = utils.LimitUTF8StringLen(operateEventDetail.AfterData, 3200)
|
||||
err = dao.CreateEntity(db, operateEventDetail)
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteOperateEventAndDetail(ctx *jxcontext.Context, deleteTime time.Time) (err error) {
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
dao.DeleteOperateEventDetail(db, deleteTime)
|
||||
dao.DeleteOperateEvent(db, deleteTime)
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -133,69 +129,3 @@ 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) {
|
||||
var (
|
||||
ebaiOrderID = "1577329467196263592"
|
||||
ebaiErr = "return not json"
|
||||
ebaiErr2 = "系统错误"
|
||||
mtStoreID = "7388603"
|
||||
mtErr = "返回结果格式不正常"
|
||||
jdUpcCode = "6952395700895"
|
||||
jdErr = "请输入用户名"
|
||||
// mtpsErr = "用户未登录"
|
||||
errMsg = ""
|
||||
)
|
||||
for _, v := range vendorIDs {
|
||||
cc := &CheckCookie{}
|
||||
var flag = false
|
||||
switch v {
|
||||
case model.VendorIDEBAI:
|
||||
resultMap, err := api.EbaiAPI.GetStoreOrderInfo(ebaiOrderID)
|
||||
if len(resultMap) < 1 && err != nil {
|
||||
if strings.Contains(err.Error(), ebaiErr) || strings.Contains(err.Error(), ebaiErr2) {
|
||||
errMsg += fmt.Sprintf(" 饿百账号:[%v]的Cookie无效了!")
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
case model.VendorIDMTWM:
|
||||
_, err := api.MtwmAPI.PackagePriceGet(mtStoreID)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), mtErr) {
|
||||
errMsg += fmt.Sprintf(" 美团账号:[%v]的Cookie无效了!")
|
||||
flag = true
|
||||
}
|
||||
globals.SugarLogger.Debugf("cookieCheck", err)
|
||||
}
|
||||
case model.VendorIDJD:
|
||||
result, err := api.JdAPI.GetJdUpcCodeByName("", jdUpcCode, 1, 5)
|
||||
if len(result) < 1 && err != nil {
|
||||
if strings.Contains(err.Error(), jdErr) {
|
||||
errMsg += fmt.Sprintf(" 京东账号:[%v]的Cookie无效了!")
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
case model.VendorIDJDShop:
|
||||
_, err := api.JdShopAPI.OrderDetail("124350112427")
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "登录") {
|
||||
errMsg += fmt.Sprintf("京东商城:[%v]的Cookie无效了!")
|
||||
flag = true
|
||||
}
|
||||
globals.SugarLogger.Debugf("cookieCheck", err)
|
||||
}
|
||||
}
|
||||
cc.VendorID = v
|
||||
cc.VendorOrgCode = ""
|
||||
if flag {
|
||||
cc.Status = "无效"
|
||||
} else {
|
||||
cc.Status = "有效"
|
||||
}
|
||||
ccList = append(ccList, cc)
|
||||
}
|
||||
if isAuto && errMsg != "" {
|
||||
globals.SugarLogger.Warnf("GetCheckVendorCookie:[%v]", errMsg)
|
||||
}
|
||||
return ccList, err
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
package financial
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"path"
|
||||
"strings"
|
||||
"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/jxutils/weixinmsg"
|
||||
"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
|
||||
}
|
||||
|
||||
func SendFilesToStores(ctx *jxcontext.Context, files []*multipart.FileHeader, title, shopName string, isAsync bool, userName string) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SendFilesToStores, fileCount:%d isAsync:%t, userName:%s", len(files), isAsync, userName)
|
||||
if len(files) == 0 {
|
||||
return "", errors.New("没有文件上传!")
|
||||
}
|
||||
|
||||
fileList := make([]*tUploadFileInfo, len(files))
|
||||
for k, fileHeader := range files {
|
||||
fileList[k] = &tUploadFileInfo{
|
||||
FileHeader: fileHeader,
|
||||
}
|
||||
fileNameParts := strings.Split(fileHeader.Filename, "_")
|
||||
if len(fileNameParts) < 3 {
|
||||
return "", fmt.Errorf("文件名:%s不规范,没有包含三个必要的部分", fileHeader.Filename)
|
||||
}
|
||||
fileList[k].StoreID = int(utils.Str2Int64WithDefault(fileNameParts[0], 0))
|
||||
if fileList[k].StoreID < 100000 || fileList[k].StoreID > 1000000 {
|
||||
return "", fmt.Errorf("文件名:%s不规范,不以合法的京西门店ID开始", fileHeader.Filename)
|
||||
}
|
||||
}
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: globals.QiniuBucket,
|
||||
Expires: 10 * 60,
|
||||
}
|
||||
upToken := putPolicy.UploadToken(api.QiniuAPI)
|
||||
cfg := &storage.Config{}
|
||||
task := tasksch.NewParallelTask("SendFilesToStores", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
fileInfo := batchItemList[0].(*tUploadFileInfo)
|
||||
fileHeader := fileInfo.FileHeader
|
||||
db := dao.GetDB()
|
||||
storeID, _ := dao.GetRealLinkStoreID(db, fileInfo.StoreID)
|
||||
file, err := fileHeader.Open()
|
||||
globals.SugarLogger.Debugf("SendFilesToStores upload file:%s", fileHeader.Filename)
|
||||
if err == nil {
|
||||
ret := storage.PutRet{}
|
||||
key := "storeBill/" + utils.Int2Str(storeID) + "_" + strings.ToLower(utils.GetUUID()) + path.Ext(fileHeader.Filename)
|
||||
formUploader := storage.NewFormUploader(cfg)
|
||||
for i := 0; i < 3; i++ {
|
||||
if err = formUploader.Put(context.Background(), &ret, upToken, key, file, fileHeader.Size, &storage.PutExtra{}); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
file.Close()
|
||||
if err == nil {
|
||||
billRec := &legacymodel.StoreBill{
|
||||
Date: time.Now(),
|
||||
Url: strings.Replace(jxutils.ComposeQiniuResURL(ret.Key), "http://", "https://", -1),
|
||||
StoreId: storeID,
|
||||
BillName: fileHeader.Filename,
|
||||
ShopName: shopName,
|
||||
BillTitle: title,
|
||||
}
|
||||
if err = dao.CreateEntity(db, billRec); err == nil {
|
||||
err = weixinmsg.NotifySaleBill(storeID, title, shopName, fmt.Sprintf("%s/billshow/?path=%s", globals.BackstageHost, billRec.Url))
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("SendFilesToStores NotifySaleBill file:%s error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
err = nil // 忽略微信发送错误
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores CreateEntity file:%s error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores file:%s failed with error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores open file:%s failed with error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
return retVal, err
|
||||
}, fileList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
hint = task.ID
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
return task.ID, 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
|
||||
}
|
||||
return bills, err
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
package initdata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/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"
|
||||
)
|
||||
|
||||
func TruncateTable(db *dao.DaoDB, tableName string) (err error) {
|
||||
_, err = dao.ExecuteSQL(db, "TRUNCATE TABLE "+tableName)
|
||||
return err
|
||||
}
|
||||
|
||||
func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *autonavi.District, placeList []*autonavi.District) (err error) {
|
||||
for _, v := range placeList {
|
||||
if v.Level <= autonavi.DistrictLevelDistrict {
|
||||
place := &model.Place{
|
||||
Code: int(utils.Str2Int64(v.Adcode)),
|
||||
Name: v.Name,
|
||||
Level: int8(v.Level),
|
||||
TelCode: v.CityCode,
|
||||
Enabled: 1,
|
||||
}
|
||||
if parent != nil {
|
||||
place.ParentCode = int(utils.Str2Int64(parent.Adcode))
|
||||
}
|
||||
dao.WrapAddIDCULEntity(place, ctx.GetUserName())
|
||||
if err = dao.CreateEntity(db, place); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = insertPlace(ctx, db, v, v.Districts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitPlace(ctx *jxcontext.Context) (err error) {
|
||||
placeList, err2 := api.AutonaviAPI.GetDistricts(autonavi.DistrictLevelDistrict, "")
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
placeList = placeList[0].Districts
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if _, err = dao.ExecuteSQL(db, `
|
||||
DELETE t1
|
||||
FROM place t1
|
||||
WHERE code < 9000000;
|
||||
`); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = insertPlace(ctx, db, nil, placeList); err != nil {
|
||||
return err
|
||||
}
|
||||
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)
|
||||
return err
|
||||
}
|
||||
|
||||
func InitVendorCategory(ctx *jxcontext.Context, vendorID int, isAsync bool) (hint string, err error) {
|
||||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||||
var cats []*model.SkuVendorCategory
|
||||
rootTask := tasksch.NewSeqTask(fmt.Sprintf("创建%s的平台分类", model.VendorChineseNames[vendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
cats, err = handler.GetVendorCategories(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 1:
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
sql := `
|
||||
DELETE
|
||||
FROM sku_vendor_category
|
||||
WHERE vendor_id = ?
|
||||
`
|
||||
if _, err = dao.ExecuteSQL(db, sql, vendorID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cat := range cats {
|
||||
dao.WrapAddIDCULEntity(cat, ctx.GetUserName())
|
||||
}
|
||||
if err = dao.CreateMultiEntities(db, cats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dao.Commit(db)
|
||||
}
|
||||
return nil, err
|
||||
}, 2)
|
||||
tasksch.HandleTask(rootTask, nil, true).Run()
|
||||
if !isAsync {
|
||||
if _, err = rootTask.GetResult(0); err == nil {
|
||||
hint = utils.Int2Str(len(cats))
|
||||
}
|
||||
} else {
|
||||
hint = rootTask.ID
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("找不到平台:%d", vendorID)
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func UploadImg4Vendors(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
// db := dao.GetDB()
|
||||
// rootTask := tasksch.NewSeqTask("合并SkuName图片至DataResource", ctx,
|
||||
// func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
// switch step {
|
||||
// case 0: // 计算SkuName中缺失的hashCode(注意是DescImg不是Img)
|
||||
// var skuNameList []*model.SkuName
|
||||
// if err = dao.GetRows(db, &skuNameList, `
|
||||
// SELECT t1.*
|
||||
// FROM sku_name t1
|
||||
// WHERE t1.desc_img <> '' AND t1.img_hash_code = ''
|
||||
// `); err == nil && len(skuNameList) > 0 {
|
||||
// calcTask := tasksch.NewParallelTask("UploadImg4Vendors calc hashCode",
|
||||
// tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError).SetParallelCount(5), ctx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// skuName := batchItemList[0].(*model.SkuName)
|
||||
// _, skuName.ImgHashCode, err = jxutils.DownloadFileByURL(skuName.DescImg)
|
||||
// if err == nil {
|
||||
// dao.UpdateEntity(db, skuName, "ImgHashCode")
|
||||
// }
|
||||
// return retVal, err
|
||||
// }, skuNameList)
|
||||
// tasksch.HandleTask(calcTask, task, false).Run()
|
||||
// _, err = calcTask.GetResult(0)
|
||||
// }
|
||||
// case 1: // 从SkuName添加缺失的图片至DataResource
|
||||
// _, err = dao.ExecuteSQL(db, `
|
||||
// INSERT INTO data_resource(created_at, updated_at, last_operator, hash_code,
|
||||
// resource_type, name, main_url, ebai_url, qiniu_url, use_type)
|
||||
// SELECT t1.created_at, t1.created_at, t1.last_operator, t1.img_hash_code,
|
||||
// CASE
|
||||
// WHEN INSTR(t1.desc_img, ".jpg") > 0 OR INSTR(t1.desc_img, ".jpeg") > 0 THEN
|
||||
// 'image/jpeg'
|
||||
// WHEN INSTR(t1.desc_img, ".png") > 0 OR INSTR(t1.desc_img, ".peg") > 0 THEN
|
||||
// 'image/png'
|
||||
// WHEN INSTR(t1.desc_img, ".gif") THEN
|
||||
// 'image/gif'
|
||||
// ELSE
|
||||
// ''
|
||||
// END resource_type,
|
||||
// CONCAT(t1.name, '_desc'), desc_img main_url, t1.desc_img_ebai ebai_url,
|
||||
// IF(INSTR(t1.desc_img, "image.jxc4.com") > 0, t1.desc_img, '') qiniu_url, 2
|
||||
// FROM sku_name t1
|
||||
// JOIN (
|
||||
// SELECT img_hash_code, MAX(id) id, COUNT(*) ct
|
||||
// FROM sku_name
|
||||
// WHERE img_hash_code <> '' AND desc_img <> ''
|
||||
// GROUP BY 1
|
||||
// ) t3 ON t3.id = t1.id
|
||||
// LEFT JOIN data_resource t2 ON (t2.main_url <> '' AND t2.main_url = t1.desc_img)
|
||||
// WHERE t1.desc_img <> '' AND t1.img_hash_code <> '' AND t2.id IS NULL;
|
||||
// `)
|
||||
// case 2: // 统一SkuName中同hashCode,不同图片地址至同一地址
|
||||
// _, err = dao.ExecuteSQL(db, `
|
||||
// UPDATE sku_name t1
|
||||
// JOIN data_resource t2 ON t2.hash_code = t1.img_hash_code AND t2.main_url <> ''
|
||||
// SET t1.desc_img = t2.main_url
|
||||
// WHERE t1.img_hash_code <> '' AND t1.desc_img <> t2.main_url;
|
||||
// `)
|
||||
// case 3: // 上传DataResource中缺失的平台图片
|
||||
// dataResList, err2 := dao.GetNeedUploadDataResource(db)
|
||||
// if err = err2; err == nil && len(dataResList) > 0 {
|
||||
// uploadTask := tasksch.NewParallelTask("批量上传图片至平台",
|
||||
// tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError).SetParallelCount(2), ctx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// dataRes := batchItemList[0].(*model.DataResource)
|
||||
// _, err = datares.UploadImage2Vendors(ctx, task, dataRes, nil, false)
|
||||
// return nil, err
|
||||
// }, dataResList)
|
||||
// tasksch.HandleTask(uploadTask, task, true).Run()
|
||||
// _, err = uploadTask.GetResult(0)
|
||||
// }
|
||||
// }
|
||||
// return result, err
|
||||
// }, 4)
|
||||
// tasksch.HandleTask(rootTask, nil, true).Run()
|
||||
// if !isAsync {
|
||||
// if _, err = rootTask.GetResult(0); err == nil {
|
||||
// hint = "1"
|
||||
// }
|
||||
// } else {
|
||||
// hint = rootTask.ID
|
||||
// }
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func getSkuNameKey(prefix, name, comment, specUnit, unit string, specQuality float32) string {
|
||||
return fmt.Sprintf("%s-%s-%f-%s-%s", prefix, name, specQuality, specUnit, unit)
|
||||
}
|
||||
@@ -1,531 +1,15 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/event"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/report"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/act"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/netspider"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
const (
|
||||
SpecialTaskID = "Running"
|
||||
TaskNameSyncStoreSku = "SyncStoreSku"
|
||||
)
|
||||
|
||||
var (
|
||||
dailyHeartbeat = []string{
|
||||
"09:00:00",
|
||||
}
|
||||
dailyWorkTimeList = []string{
|
||||
"20:30:00",
|
||||
}
|
||||
dailyWorkTimeList2 = []string{
|
||||
"02:00:00",
|
||||
}
|
||||
priceReferTimeList = []string{
|
||||
"03:00:00",
|
||||
}
|
||||
checkCookieList = []string{
|
||||
"08:00:00",
|
||||
"12:00:00",
|
||||
"18:00:00",
|
||||
}
|
||||
createStorePriceTimeList = []string{
|
||||
"04:00:00",
|
||||
}
|
||||
refreshPageActTimeList = []string{
|
||||
"7:00:00",
|
||||
"8:00:00",
|
||||
"9:00:00",
|
||||
"10:00:00",
|
||||
"11:00:00",
|
||||
"12:00:00",
|
||||
"13:00:00",
|
||||
"14:00:00",
|
||||
"15:00:00",
|
||||
"16:00:00",
|
||||
"17:00:00",
|
||||
"18:00:00",
|
||||
"19:00:00",
|
||||
"22:00:00",
|
||||
}
|
||||
ChangeStoreSkuSaleStatusList = []string{
|
||||
"7:00:00",
|
||||
"8:00:00",
|
||||
"9:00:00",
|
||||
"10:00:00",
|
||||
"11:00:00",
|
||||
"12:00:00",
|
||||
"13:00:00",
|
||||
"14:00:00",
|
||||
"15:00:00",
|
||||
"16:00:00",
|
||||
"17:00:00",
|
||||
"18:00:00",
|
||||
"19:00:00",
|
||||
"20:00:00",
|
||||
}
|
||||
openRemoteStoreTimeList = []string{
|
||||
"04:30:00",
|
||||
"23:30:00",
|
||||
}
|
||||
updateActStatusTimeList = []string{
|
||||
"00:01:00",
|
||||
}
|
||||
sendSecKillWarnList = []string{
|
||||
"9:00:00",
|
||||
}
|
||||
autoPayForPopluarManList = []string{
|
||||
"10:30:00",
|
||||
}
|
||||
|
||||
autoSaleStoreSkuTimeList = []string{
|
||||
cms.AutoSaleAtStr,
|
||||
}
|
||||
|
||||
backUpStoreSkuBindList = []string{
|
||||
"23:30:00",
|
||||
}
|
||||
|
||||
exSyncList = []string{
|
||||
"11:30:00",
|
||||
}
|
||||
|
||||
importantTaskMap = &sync.Map{}
|
||||
|
||||
cancelPayTimeOutOrderList = localjx.GetHalfHoursList()
|
||||
discountActJxList = localjx.GetDiscountActHoursList()
|
||||
|
||||
ebaiStorePageCookieExdTOKEN string
|
||||
ebaiStorePageCookieWMUSS2 string
|
||||
ebaiStorePageCookieWMSTOKEN2 string
|
||||
ebaiStorePageCookieWMUSS string
|
||||
ebaiStorePageCookieWMSTOKEN string
|
||||
mtwmCookieStr string
|
||||
mtpsStoreToken string
|
||||
jd2StorePageCookie string
|
||||
JdStorePageCookie string
|
||||
yinbaoCookie string
|
||||
feiePageCookie string
|
||||
jdStorePageEarning string
|
||||
jdsCookie string
|
||||
)
|
||||
|
||||
func GetImportantTaskID(taskName string) string {
|
||||
if value, ok := importantTaskMap.Load(taskName); ok {
|
||||
return value.(string)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func SaveImportantTaskID(taskName, taskID string) {
|
||||
importantTaskMap.Store(taskName, taskID)
|
||||
}
|
||||
|
||||
func IsImportantTaskRunning(taskName string) bool {
|
||||
taskID := GetImportantTaskID(taskName)
|
||||
if taskID == "" {
|
||||
return false
|
||||
} else if taskID == SpecialTaskID {
|
||||
return true
|
||||
}
|
||||
return tasksch.IsTaskRunning(taskID)
|
||||
}
|
||||
|
||||
func Init() {
|
||||
if globals.IsProductEnv() {
|
||||
ScheduleTimerFunc("doDailyWork", doDailyWork, dailyWorkTimeList)
|
||||
|
||||
ScheduleTimerFunc("doDailyWork2", doDailyWork2, dailyWorkTimeList2)
|
||||
|
||||
// ScheduleTimerFuncByInterval(func() {
|
||||
// orderman.SaveJdsOrders(jxcontext.AdminCtx, time.Now().Add(-20*time.Minute), time.Now())
|
||||
// }, 10*time.Second, 10*time.Minute)
|
||||
|
||||
//京东的订单信息解密密钥获取
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
jdshop.InitKey()
|
||||
}, 10*time.Second, 8*time.Hour)
|
||||
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
RefreshRealMobile(jxcontext.AdminCtx, model.VendorIDEBAI, time.Now().Add(-24*time.Hour), utils.DefaultTimeValue, false, true)
|
||||
}, 5*time.Second, 1*time.Hour)
|
||||
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
defsch.FixedScheduler.ConfirmSelfTakeOrders(jxcontext.AdminCtx, []int{model.VendorIDJD}, time.Now().Add(-48*time.Hour), time.Now().Add(-30*time.Minute), true, true)
|
||||
}, 5*time.Second, 10*time.Minute)
|
||||
|
||||
ScheduleTimerFunc("auto enable remote store", func() {
|
||||
cms.EnableHaveRestStores(jxcontext.AdminCtx, false, true)
|
||||
cms.OpenRemoteStoreByJxStatus(jxcontext.AdminCtx, nil, nil, false, false, true)
|
||||
}, openRemoteStoreTimeList)
|
||||
|
||||
ScheduleTimerFunc("SaveAndSendAlarmVendorSnapshot", func() {
|
||||
cms.SaveAndSendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, nil, false)
|
||||
}, cms.WatchVendorStoreTimeList)
|
||||
|
||||
ScheduleTimerFunc("RefreshPageActs", func() {
|
||||
act.RefreshPageActs(jxcontext.AdminCtx, []int{model.VendorIDEBAI}, time.Now().Add(-30*24*time.Hour), false)
|
||||
}, refreshPageActTimeList)
|
||||
ScheduleTimerFunc("UpdateActStatusByTime", func() {
|
||||
dao.UpdateActStatusByTime(dao.GetDB(), time.Now())
|
||||
}, updateActStatusTimeList)
|
||||
ScheduleScoreStore()
|
||||
ScheduleCheckStoreAlert()
|
||||
ScheduleTimerFunc("ChangeStoreSkuSaleStatus", func() {
|
||||
cms.CurVendorSync.ChangeStoreSkuSaleStatus(jxcontext.AdminCtx, 0, true, true)
|
||||
}, ChangeStoreSkuSaleStatusList)
|
||||
ScheduleTimerFunc("BeginSavePriceRefer", func() {
|
||||
report.BeginSavePriceRefer(jxcontext.AdminCtx, nil, nil, true, true)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("CreateStorePriceScore", func() {
|
||||
cms.CreateStorePriceScore(jxcontext.AdminCtx)
|
||||
}, createStorePriceTimeList)
|
||||
ScheduleTimerFunc("AutoFocusStoreSkusForTopSkus", func() {
|
||||
cms.AutoFocusStoreSkusForTopSkus(jxcontext.AdminCtx, true, true)
|
||||
}, createStorePriceTimeList)
|
||||
ScheduleTimerFunc("GetCheckVendorCookie", func() {
|
||||
event.GetCheckVendorCookie(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM, model.VendorIDMTPS, model.VendorIDJDShop}, true)
|
||||
}, checkCookieList)
|
||||
ScheduleTimerFunc("SendSeckillSkusCountMsg", func() {
|
||||
cms.SendSeckillSkusCountMsg(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM}, false, true)
|
||||
}, sendSecKillWarnList)
|
||||
ScheduleTimerFunc("每日报警心跳", func() {
|
||||
globals.SugarLogger.Warnf("每日报警心跳,这不是报警。启动时间:%s", cms.GetServiceInfo(jxcontext.AdminCtx)["startupTime"])
|
||||
}, dailyHeartbeat)
|
||||
ScheduleTimerFunc("AutoPayForPopluarMan", func() {
|
||||
localjx.AutoPayForPopluarMan(jxcontext.AdminCtx)
|
||||
}, autoPayForPopluarManList)
|
||||
ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
|
||||
localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
|
||||
}, cancelPayTimeOutOrderList)
|
||||
ScheduleTimerFunc("BackUpStoreSkuBind", func() {
|
||||
cms.BackUpStoreSkuBind(jxcontext.AdminCtx, true, true)
|
||||
}, backUpStoreSkuBindList)
|
||||
ScheduleTimerFunc("SendNoCatSkusToOperater", func() {
|
||||
cms.SendNoCatSkusToOperater(jxcontext.AdminCtx)
|
||||
}, autoPayForPopluarManList)
|
||||
ScheduleTimerFunc("CleanStoreIsBoughtMatter", func() {
|
||||
cms.CleanStoreIsBoughtMatter(jxcontext.AdminCtx)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("CleanUserOrderSMSMark", func() {
|
||||
cms.CleanUserOrderSMSMark(jxcontext.AdminCtx)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("exSync", func() {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
storeList []int
|
||||
exSyncStoreIDList string
|
||||
syncFlag = 0
|
||||
)
|
||||
syncFlag = model.SyncFlagPriceMask
|
||||
if (time.Now().Unix()/24*3600)%10 == 0 {
|
||||
syncFlag |= model.SyncFlagSaleMask
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "exSyncStoreIDList", model.ConfigTypeSys, ""); err == nil {
|
||||
exSyncStoreIDList = configs[0].Value
|
||||
}
|
||||
storeIDList := strings.Split(exSyncStoreIDList, ",")
|
||||
for _, v := range storeIDList {
|
||||
storeList = append(storeList, int(utils.Str2Int64(v)))
|
||||
}
|
||||
cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetMultiStoreVendorIDs(), storeList, false, nil, []int{27379}, syncFlag, true, true)
|
||||
}, exSyncList)
|
||||
ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
|
||||
localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
|
||||
}, []string{
|
||||
"22:00:00",
|
||||
})
|
||||
ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
|
||||
act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
|
||||
}, discountActJxList)
|
||||
ScheduleTimerFunc("RefreshUserMemberStatus", func() {
|
||||
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
|
||||
}, updateActStatusTimeList)
|
||||
}
|
||||
ScheduleTimerFunc("AutoSaleStoreSku", func() {
|
||||
cms.AutoSaleStoreSku(jxcontext.AdminCtx, nil, false)
|
||||
}, autoSaleStoreSkuTimeList)
|
||||
|
||||
if beego.BConfig.RunMode == "jxgy" {
|
||||
ScheduleTimerFunc("SyncMatterC4ToGy", func() {
|
||||
cms.SyncMatterC4ToGy(jxcontext.AdminCtx, true, true)
|
||||
}, dailyWorkTimeList)
|
||||
}
|
||||
if beego.BConfig.RunMode == "beta" {
|
||||
ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
|
||||
localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
|
||||
}, cancelPayTimeOutOrderList)
|
||||
ScheduleTimerFunc("GetAndStoreCitiesShops", func() {
|
||||
netspider.GetAndStoreCitiesShops(jxcontext.AdminCtx, nil, nil, 0, 0, false, false)
|
||||
}, []string{
|
||||
"04:05:06",
|
||||
})
|
||||
//京东的订单信息解密密钥获取
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
jdshop.InitKey()
|
||||
}, 10*time.Second, 8*time.Hour)
|
||||
ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
|
||||
act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
|
||||
}, discountActJxList)
|
||||
ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
|
||||
localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
|
||||
}, []string{
|
||||
"22:00:00",
|
||||
})
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieExdTOKEN", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieExdTOKEN = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMUSS2", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieWMUSS2 = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMSTOKEN2", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieWMSTOKEN2 = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMUSS", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieWMUSS = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMSTOKEN", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieWMSTOKEN = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtwmCookieStr", model.ConfigTypeCookie, ""); err == nil {
|
||||
mtwmCookieStr = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtpsStoreToken", model.ConfigTypeCookie, ""); err == nil {
|
||||
mtpsStoreToken = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
JdStorePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageEarning", model.ConfigTypeCookie, ""); err == nil {
|
||||
jdStorePageEarning = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jd2StorePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
jd2StorePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "feiePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
feiePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdsCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
jdsCookie = configs[0].Value
|
||||
api.JdShopAPI.SetCookieWithStr(jdsCookie)
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "yinbaoCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
yinbaoCookie := configs[0].Value
|
||||
api.YinBaoAPI.SetCookie(".POSPALAUTH30220", yinbaoCookie)
|
||||
}
|
||||
if globals.Jd2OrgCode != "" {
|
||||
api.Jd2API.SetJdCookie(jd2StorePageCookie)
|
||||
}
|
||||
api.EbaiAPI.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
|
||||
api.EbaiAPI.SetCookie("WMUSS", ebaiStorePageCookieWMUSS)
|
||||
api.EbaiAPI.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN)
|
||||
api.Ebai2API.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
|
||||
api.Ebai2API.SetCookie("WMUSS", ebaiStorePageCookieWMUSS2)
|
||||
api.Ebai2API.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN2)
|
||||
api.MtwmAPI.SetCookieWithStr(mtwmCookieStr)
|
||||
api.MtpsAPI.SetCookie("token", mtpsStoreToken)
|
||||
api.JdAPI.SetJdCookie(JdStorePageCookie)
|
||||
api.JdAPI.SetCookie("user", jdStorePageEarning)
|
||||
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName, JdStorePageCookie)
|
||||
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName2, JdStorePageCookie)
|
||||
api.FeieAPI.SetCookieWithStr(feiePageCookie)
|
||||
}
|
||||
|
||||
func syncStoreSku() {
|
||||
syncFlag := 0
|
||||
// syncFlag := model.SyncFlagPriceMask
|
||||
// if (time.Now().Unix()/24*3600)%10 == 0 {
|
||||
// syncFlag |= model.SyncFlagSaleMask
|
||||
// }
|
||||
task := tasksch.NewParallelTask("同步京西与平台数据", nil, jxcontext.AdminCtx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
errList := errlist.New()
|
||||
db := dao.GetDB()
|
||||
switch step {
|
||||
case 0:
|
||||
errList.AddErr(cms.DeleteSkuNameExPrefixOverdue(db))
|
||||
errList.AddErr(cms.SetMultiStoreSkuSyncModifyStatus(db, partner.GetMultiStoreVendorIDs()))
|
||||
|
||||
_, err = cms.CurVendorSync.LoopMultiStoresVendors(jxcontext.AdminCtx, db, "同步多门店平台商品库", false, true,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorInfo := batchItemList[0].(*cms.MultiStoreVendorInfo)
|
||||
_, err = cms.FullSyncVendorStuff(jxcontext.AdminCtx, task, vendorInfo.VendorID, vendorInfo.OrgCode, false, true)
|
||||
return retVal, err
|
||||
})
|
||||
errList.AddErr(err)
|
||||
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{0}, nil, false, nil, []int{27379}, syncFlag, true, true)
|
||||
// _, err = cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, db, partner.GetMultiStoreVendorIDs(), nil, false, []int{27379}, true, true)
|
||||
errList.AddErr(err)
|
||||
case 1:
|
||||
//TODO 暂时不同步银豹(可能要从银豹到京西),2020-04-27
|
||||
errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, []int{1, 3}))
|
||||
|
||||
// errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, partner.GetSingleStoreVendorIDs()))
|
||||
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, []int{1, 3}, nil, false, true, cms.AmendPruneAll, false)
|
||||
|
||||
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, partner.GetSingleStoreVendorIDs(), nil, false, true, cms.AmendPruneAll, false)
|
||||
errList.AddErr(err)
|
||||
|
||||
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
|
||||
taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{1, 3, 5}, nil, false, nil, nil, syncFlag, true, true)
|
||||
// taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetSingleStoreVendorIDs(), nil, false, nil, nil, syncFlag, true, true)
|
||||
|
||||
errList.AddErr(err2)
|
||||
SaveImportantTaskID(TaskNameSyncStoreSku, taskID)
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return retVal, err
|
||||
}, []int{0, 1})
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
}
|
||||
|
||||
func doDailyWork2() {
|
||||
globals.SugarLogger.Debug("doDailyWork2")
|
||||
|
||||
//同步京东商城门店的商品
|
||||
cms.CurVendorSync.SyncJdsStoresSkus(jxcontext.AdminCtx, nil, true, true)
|
||||
//刷新京东商城的门店库存
|
||||
cms.SyncJdsStoreStock(jxcontext.AdminCtx, true, true)
|
||||
}
|
||||
|
||||
func doDailyWork() {
|
||||
globals.SugarLogger.Debug("doDailyWork")
|
||||
|
||||
//同步商品额外前缀和水印图(打标记)
|
||||
cms.SyncSkuExperfixAndWatermark(jxcontext.AdminCtx)
|
||||
|
||||
dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus)
|
||||
cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), nil, nil, true, true)
|
||||
|
||||
syncStoreSku()
|
||||
InitEx()
|
||||
cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true)
|
||||
netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true)
|
||||
|
||||
// 每天补全前一天与当天的订单
|
||||
curDate := utils.Time2Date(time.Now())
|
||||
orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, nil, 0, curDate.Add(-72*time.Hour), curDate, true, true)
|
||||
//订单门店归属补漏
|
||||
//fromDate, toDate都不传默认刷新当前天5天以前的订单,只传fromDate默认刷新fromDate到当天的订单
|
||||
//只传toDate默认刷新toDate到5天以前的订单
|
||||
orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true)
|
||||
//刷新京东门店的等级
|
||||
cms.RefreshJdLevel(jxcontext.AdminCtx)
|
||||
//删除操作日志
|
||||
// event.DeleteOperateEventAndDetail(jxcontext.AdminCtx, time.Now().AddDate(0, -3, 0))
|
||||
//禁用没有绑定的门店
|
||||
cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true)
|
||||
//刷新物料订单状态
|
||||
localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx)
|
||||
//同步银豹到京西
|
||||
// cms.CurVendorSync.SyncStoreSkusFromYb(jxcontext.AdminCtx, nil, true, true)
|
||||
//刷新京东商城订单结算价
|
||||
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, time.Now().AddDate(0, 0, -2).Format("20060102"), time.Now().Format("20060102"))
|
||||
//同步上架京东商城待售商品
|
||||
cms.RefreshJdsSkusStatus(jxcontext.AdminCtx)
|
||||
//同步美团配送与否状态及美团门店是否存在
|
||||
cms.SetMTPSStatus(jxcontext.AdminCtx, 0, 0)
|
||||
//售后单如果超过12小时没有审核,就自动通过
|
||||
RefreshAfsOrderStatusAccess(jxcontext.AdminCtx)
|
||||
}
|
||||
|
||||
func RefreshAfsOrderStatusAccess(ctx *jxcontext.Context) {
|
||||
var (
|
||||
offset = 0
|
||||
pageSize = 9999
|
||||
db = dao.GetDB()
|
||||
)
|
||||
afsOrderList, _, err := dao.GetAfsOrdersByPage(db, "", "", "", time.Now().AddDate(0, 0, -7), time.Now(), offset, pageSize)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, v := range afsOrderList {
|
||||
if v.Status == model.AfsOrderStatusWait4Approve && time.Now().Sub(v.AfsCreatedAt).Hours() > 12 {
|
||||
defsch.FixedScheduler.AgreeOrRefuseRefund(ctx, v.AfsOrderID, v.VendorID, model.AfsTypePartRefund, "超时系统同意")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RefreshRealMobile(ctx *jxcontext.Context, vendorID int, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debug("RefreshRealMobile")
|
||||
|
||||
handler := partner.GetPurchasePlatformFromVendorID(vendorID)
|
||||
if handler == nil {
|
||||
return "", fmt.Errorf("不合法的vendorID:%d", vendorID)
|
||||
}
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM goods_order
|
||||
WHERE vendor_id = ? AND consignee_mobile2 = ''
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
vendorID,
|
||||
}
|
||||
if !utils.IsTimeZero(fromTime) {
|
||||
sql += " AND order_created_at >= ?"
|
||||
sqlParams = append(sqlParams, fromTime)
|
||||
}
|
||||
if !utils.IsTimeZero(toTime) {
|
||||
sql += " AND order_created_at <= ?"
|
||||
sqlParams = append(sqlParams, toTime)
|
||||
}
|
||||
var orderList []*model.GoodsOrder
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetRows(db, &orderList, sql, sqlParams...); err == nil && len(orderList) > 0 {
|
||||
task := tasksch.NewParallelTask("misc RefreshRealMobile", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
order := batchItemList[0].(*model.GoodsOrder)
|
||||
mobile, err2 := handler.GetOrderRealMobile(ctx, order)
|
||||
if err = err2; err == nil {
|
||||
mobile = jxutils.FormalizeMobile(mobile)
|
||||
if jxutils.IsStringLikeMobile(mobile) && strings.Index(order.ConsigneeMobile, mobile) == -1 {
|
||||
order.ConsigneeMobile2 = mobile
|
||||
_, err = dao.UpdateEntity(db, order, "ConsigneeMobile2")
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Infof("RefreshRealMobile orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return nil, err
|
||||
}, orderList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
hint = task.ID
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
// 按时间序列循环
|
||||
|
||||
@@ -1,396 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
enableScheduleRefreshStore = true
|
||||
taskParallelCount = 4
|
||||
specialSkuNameKeyWord = "温馨提示"
|
||||
startOpStoreStockNumber = 0
|
||||
endOpStoreStockNumber = model.MaxStoreSkuStockQty
|
||||
)
|
||||
|
||||
var (
|
||||
isDaemonRunning = false
|
||||
vendorList = map[int]bool{
|
||||
model.VendorIDMTWM: true,
|
||||
model.VendorIDEBAI: true,
|
||||
}
|
||||
storeListQueueData = map[bool]*StoreListQueueData{
|
||||
true: &StoreListQueueData{},
|
||||
false: &StoreListQueueData{},
|
||||
}
|
||||
// vendorStoreRefreshTimeList = map[int][]string {
|
||||
// model.VendorIDMTWM: []string {
|
||||
// //start and end time for JXGY
|
||||
// "22:00:00",
|
||||
// "00:00:00",
|
||||
// //start and end time for JXCS
|
||||
// "22:10:00",
|
||||
// "00:10:00",
|
||||
// },
|
||||
// model.VendorIDEBAI: []string {
|
||||
// "22:20:00",
|
||||
// "06:00:00",
|
||||
|
||||
// "22:30:00",
|
||||
// "06:10:00",
|
||||
// },
|
||||
// }
|
||||
|
||||
// vendorStartEndStoreTime = map[int][]int16 {
|
||||
// model.VendorIDMTWM: []int16 {
|
||||
// int16(2200),//start time
|
||||
// int16(2355),//end time
|
||||
// },
|
||||
// model.VendorIDEBAI: []int16 {
|
||||
// int16(5),
|
||||
// int16(2355),
|
||||
// },
|
||||
// }
|
||||
)
|
||||
|
||||
type StoreListQueueData struct {
|
||||
waitQueue []*cms.StoreExt
|
||||
processQueue []*cms.StoreExt
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *StoreListQueueData) GetProcessQueue() (outQueue []*cms.StoreExt) {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
outQueue = append(outQueue, s.processQueue...)
|
||||
return outQueue
|
||||
}
|
||||
|
||||
func (s *StoreListQueueData) InsertToWaitQueue(storeInfo *cms.StoreExt) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
s.waitQueue = append(s.waitQueue, storeInfo)
|
||||
}
|
||||
|
||||
func (s *StoreListQueueData) ClearProcessQueue() {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
if len(s.processQueue) > 0 {
|
||||
s.processQueue = []*cms.StoreExt{}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreListQueueData) TransferWaitQueueToProcessQueue() {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
if len(s.processQueue) == 0 && len(s.waitQueue) > 0 {
|
||||
for _, value := range s.waitQueue {
|
||||
s.processQueue = append(s.processQueue, value)
|
||||
}
|
||||
s.waitQueue = []*cms.StoreExt{}
|
||||
}
|
||||
}
|
||||
|
||||
func AddOrDelExtraStoreOptime(ctx *jxcontext.Context, vendorID int, vendorOrgCode string, storeID int, vendorStoreID string, storeInfo *model.Store, startOpStoreTime, endOpStoreTime int16, needAddTime bool) bool {
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if needAddTime {
|
||||
opTimeList = []int16{startOpStoreTime, endOpStoreTime}
|
||||
}
|
||||
handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreHandler)
|
||||
return handler.UpdateStoreOpTime(ctx, vendorOrgCode, storeID, vendorStoreID, opTimeList) == nil
|
||||
}
|
||||
|
||||
func GetStockValue(isStart bool) int {
|
||||
if isStart {
|
||||
return startOpStoreStockNumber
|
||||
} else {
|
||||
return endOpStoreStockNumber
|
||||
}
|
||||
}
|
||||
|
||||
// func GetOpStoreTime(vendorID int) (startTime, endTime int16) {
|
||||
// startTime = vendorStartEndStoreTime[vendorID][0]
|
||||
// endTime = vendorStartEndStoreTime[vendorID][1]
|
||||
// return startTime, endTime
|
||||
// }
|
||||
|
||||
func IsSpecialSku(name string) bool {
|
||||
return strings.Contains(name, specialSkuNameKeyWord)
|
||||
}
|
||||
|
||||
func SetSkuStock(isStart bool, storeSkuNameList []*partner.SkuNameInfo) {
|
||||
for _, skuNameInfo := range storeSkuNameList {
|
||||
for _, skuInfo := range skuNameInfo.SkuList {
|
||||
if IsSpecialSku(skuNameInfo.Name) || IsSpecialSku(skuInfo.SkuName) {
|
||||
skuInfo.Stock = endOpStoreStockNumber
|
||||
} else {
|
||||
skuInfo.Stock = GetStockValue(isStart)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetSpecialSkuStatus(ctx *jxcontext.Context, vendorID int, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuNameList []*partner.SkuNameInfo) {
|
||||
singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
|
||||
for _, skuNameInfo := range storeSkuNameList {
|
||||
for _, skuInfo := range skuNameInfo.SkuList {
|
||||
if IsSpecialSku(skuNameInfo.Name) || IsSpecialSku(skuInfo.SkuName) {
|
||||
storeSkuList := []*partner.StoreSkuInfo{&skuInfo.StoreSkuInfo}
|
||||
singleStoreHandler.UpdateStoreSkusStatus(ctx, vendorOrgCode, storeID, vendorStoreID, storeSkuList, model.SkuStatusNormal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetFilterStoreSkuList(storeSkuList []*partner.StoreSkuInfo) (storeSkuListOut []*partner.StoreSkuInfo) {
|
||||
for _, value := range storeSkuList {
|
||||
if value.SkuID != 0 {
|
||||
storeSkuListOut = append(storeSkuListOut, value)
|
||||
}
|
||||
}
|
||||
|
||||
return storeSkuListOut
|
||||
}
|
||||
|
||||
func GetStoreList(ctx *jxcontext.Context) (storeList []*cms.StoreExt, err error) {
|
||||
storeInfo, err := cms.GetStores(ctx, "", map[string]interface{}{}, 0, -1, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0)
|
||||
storeList = storeInfo.Stores
|
||||
return storeList, err
|
||||
}
|
||||
|
||||
func GetFilterStoreList(storeList []*cms.StoreExt, vendorMap, storeIDMap map[int]bool) (outStoreList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
//filter for storeID
|
||||
if len(storeIDMap) > 0 {
|
||||
if _, ok := storeIDMap[storeID]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
for _, vendorStoreInfo := range storeInfo.StoreMaps {
|
||||
vendorID := vendorStoreInfo.VendorID
|
||||
//filter for vendorID
|
||||
if len(vendorMap) > 0 {
|
||||
if _, ok := vendorMap[vendorID]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if _, ok := vendorList[vendorID]; !ok {
|
||||
continue
|
||||
}
|
||||
temp := *storeInfo
|
||||
newStoreInfo := &temp
|
||||
newStoreInfo.StoreMaps = []*model.StoreMap{vendorStoreInfo}
|
||||
outStoreList = append(outStoreList, newStoreInfo)
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
func StartOrEndOpStore(ctx *jxcontext.Context, isStart bool, vendorIDList []int, storeIDList []int, startTime, endTime int16, isAsync, isContinueWhenError bool) (retVal interface{}, err error) {
|
||||
storeList, err := GetStoreList(ctx)
|
||||
vendorMap := make(map[int]bool)
|
||||
for _, vendorID := range vendorIDList {
|
||||
vendorMap[vendorID] = true
|
||||
}
|
||||
storeIDMap := make(map[int]bool)
|
||||
for _, storeID := range storeIDList {
|
||||
storeIDMap[storeID] = true
|
||||
}
|
||||
storeList = GetFilterStoreList(storeList, vendorMap, storeIDMap)
|
||||
return StartOrEndOpStoreEx(ctx, isStart, startTime, endTime, isAsync, isContinueWhenError, storeList)
|
||||
}
|
||||
|
||||
func StartOrEndOpStoreEx(ctx *jxcontext.Context, isStart bool, startTime, endTime int16, isAsync, isContinueWhenError bool, storeList []*cms.StoreExt) (retVal interface{}, err error) {
|
||||
startProcessTime := time.Now().Unix()
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore start time: %v", time.Now())
|
||||
|
||||
if len(storeList) > 0 {
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeListValue := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeListValue.ID
|
||||
for _, vendorListValue := range storeListValue.StoreMaps {
|
||||
vendorID := vendorListValue.VendorID
|
||||
startOpStoreTime := vendorListValue.FakeOpenStart
|
||||
endOpStoreTime := vendorListValue.FakeOpenStop
|
||||
//startOpStoreTime, endOpStoreTime := GetOpStoreTime(vendorID)
|
||||
if startTime != 0 && endTime != 0 {
|
||||
startOpStoreTime = startTime
|
||||
endOpStoreTime = endTime
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore SetStoreOptime:%d do:%d", startTime, endTime)
|
||||
}
|
||||
if isStart && (startOpStoreTime == 0 || endOpStoreTime == 0) {
|
||||
continue
|
||||
}
|
||||
vendorStoreID := vendorListValue.VendorStoreID
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore storeID:%d vendorID:%d vendorStoreID:%s", storeID, vendorID, vendorStoreID)
|
||||
singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
|
||||
storeSkuNameList, err := singleStoreHandler.GetStoreSkusFullInfo(ctx, task, storeID, vendorStoreID, nil)
|
||||
if err != nil {
|
||||
baseapi.SugarLogger.Errorf("StartOrEndOpStore GetStoreSkusFullInfo error:%v storeID:%d vendorID:%d vendorStoreID:%s", err, storeID, vendorID, vendorStoreID)
|
||||
} else {
|
||||
SetSkuStock(isStart, storeSkuNameList)
|
||||
SetSpecialSkuStatus(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, storeSkuNameList)
|
||||
storeSkuList := putils.StoreSkuFullList2Bare(storeSkuNameList)
|
||||
if vendorID == model.VendorIDMTWM {
|
||||
storeSkuList = GetFilterStoreSkuList(storeSkuList)
|
||||
}
|
||||
if len(storeSkuList) > 0 {
|
||||
if !isStart {
|
||||
AddOrDelExtraStoreOptime(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, &storeListValue.Store, startOpStoreTime, endOpStoreTime, false)
|
||||
}
|
||||
|
||||
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品库存", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
_, err = singleStoreHandler.UpdateStoreSkusStock(ctx, vendorListValue.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList)
|
||||
return nil, 0, err
|
||||
}, ctx, task, storeSkuList, singleStoreHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStock), true)
|
||||
|
||||
if isStart {
|
||||
AddOrDelExtraStoreOptime(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, &storeListValue.Store, startOpStoreTime, endOpStoreTime, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
taskName := ""
|
||||
if isStart {
|
||||
taskName = "开启平台商店的额外营业时间"
|
||||
} else {
|
||||
taskName = "结束平台商店的额外营业时间"
|
||||
}
|
||||
task := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetParallelCount(taskParallelCount), ctx, taskFunc, storeList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if isAsync {
|
||||
retVal = task.ID
|
||||
} else {
|
||||
_, err = task.GetResult(0)
|
||||
if err != nil {
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore tasksch error:%v", err)
|
||||
}
|
||||
retVal = "1"
|
||||
}
|
||||
}
|
||||
endProcessTime := time.Now().Unix()
|
||||
diff := endProcessTime - startProcessTime
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore end time: %v", time.Now())
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore cost time: %d sec", diff)
|
||||
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func IsJXCS() bool {
|
||||
return globals.IsMainProductEnv()
|
||||
}
|
||||
|
||||
// func GetVendorStoreRefreshTime(vendorID int) (startTimeList, stopTimeList []string) {
|
||||
// isJXCS := globals.IsMainProductEnv()
|
||||
// refreshTimeList := vendorStoreRefreshTimeList[vendorID]
|
||||
// if isJXCS {
|
||||
// startTimeList = []string{refreshTimeList[2]}
|
||||
// stopTimeList = []string{refreshTimeList[3]}
|
||||
// } else {
|
||||
// startTimeList = []string{refreshTimeList[0]}
|
||||
// stopTimeList = []string{refreshTimeList[1]}
|
||||
// }
|
||||
// return startTimeList, stopTimeList
|
||||
// }
|
||||
|
||||
// func RefreshStore(vendorID int) {
|
||||
// ctx := jxcontext.AdminCtx
|
||||
// startTimeList, stopTimeList := GetVendorStoreRefreshTime(vendorID)
|
||||
// vendorIDList := []int{vendorID}
|
||||
// storeIDList := []int{}
|
||||
// ScheduleTimerFunc("StartOpStore", func() {
|
||||
// if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
|
||||
// StartOrEndOpStore(ctx, true, vendorIDList, storeIDList, 0, 0, false, true)
|
||||
// }
|
||||
// }, startTimeList)
|
||||
// ScheduleTimerFunc("EndOpStore", func() {
|
||||
// if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
|
||||
// StartOrEndOpStore(ctx, false, vendorIDList, storeIDList, 0, 0, false, true)
|
||||
// }
|
||||
// }, stopTimeList)
|
||||
// }
|
||||
|
||||
func InitEx() {
|
||||
// for index, value := range vendorList {
|
||||
// if value {
|
||||
// RefreshStore(index)
|
||||
// }
|
||||
// }
|
||||
if enableScheduleRefreshStore && IsJXCS() {
|
||||
ctx := jxcontext.AdminCtx
|
||||
storeList, err := GetStoreList(ctx)
|
||||
storeList = GetFilterStoreList(storeList, map[int]bool{}, map[int]bool{})
|
||||
if err == nil {
|
||||
for _, storeInfo := range storeList {
|
||||
for _, vendorStoreInfo := range storeInfo.StoreMaps {
|
||||
startOpStoreTime := vendorStoreInfo.FakeOpenStart
|
||||
endOpStoreTime := vendorStoreInfo.FakeOpenStop
|
||||
if startOpStoreTime == 0 || endOpStoreTime == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
startTime := jxutils.OperationTime2StrWithSecond(startOpStoreTime)
|
||||
ScheduleTimerFuncOnce("StartOpStore", func(param interface{}) {
|
||||
if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
|
||||
storeInfo := param.(*cms.StoreExt)
|
||||
storeListQueueData[true].InsertToWaitQueue(storeInfo)
|
||||
}
|
||||
}, startTime, storeInfo)
|
||||
|
||||
stopTime := jxutils.OperationTime2StrWithSecond(endOpStoreTime)
|
||||
ScheduleTimerFuncOnce("EndOpStore", func(param interface{}) {
|
||||
storeInfo := param.(*cms.StoreExt)
|
||||
storeListQueueData[false].InsertToWaitQueue(storeInfo)
|
||||
}, stopTime, storeInfo)
|
||||
}
|
||||
}
|
||||
if !isDaemonRunning {
|
||||
isDaemonRunning = true
|
||||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
periodlyFunc := func() {
|
||||
for isStart, value := range storeListQueueData {
|
||||
storeList := value.GetProcessQueue()
|
||||
if len(storeList) > 0 {
|
||||
StartOrEndOpStoreEx(ctx, isStart, 0, 0, false, true, storeList)
|
||||
}
|
||||
}
|
||||
for _, value := range storeListQueueData {
|
||||
value.ClearProcessQueue()
|
||||
value.TransferWaitQueueToProcessQueue()
|
||||
}
|
||||
}
|
||||
PeriodlyCall(60*time.Second, periodlyFunc)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
taskSeq := tasksch.NewSeqTask("启动监听-定时刷新平台商店的额外营业时间", ctx, taskSeqFunc, 1)
|
||||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PeriodlyCall(d time.Duration, handler func()) {
|
||||
ticker := time.NewTicker(d)
|
||||
for _ = range ticker.C {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
func TestStartOrEndOpStore(t *testing.T) {
|
||||
StartOrEndOpStore(jxcontext.AdminCtx, true, nil, nil, 0, 0, false, true)
|
||||
}
|
||||
@@ -1,509 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/refutil"
|
||||
)
|
||||
|
||||
const (
|
||||
EnableCheckStoreAlert = true
|
||||
EnableSendStoreAlert = true
|
||||
|
||||
IncludeToday = true
|
||||
CheckStoreAlertOneMonthDayNum = 30
|
||||
CheckStoreAlertOneDayNum = 1
|
||||
CheckStoreAlertOneWeekDayNum = 7
|
||||
MonthCheckOnWeekDay = 1
|
||||
|
||||
AlertTypePickTimeOrderDaDa = 0
|
||||
AlertTypeBadCommentOrder = 1
|
||||
AlertTypeAbsentGoodsOrder = 2
|
||||
AlertTypeStandardFinishTimeOrderSelfDelivery = 3
|
||||
AlertTypeStandardPickUpTimeOrderDaDa = 4
|
||||
|
||||
ColorRed = "red"
|
||||
ColorYellow = "yellow"
|
||||
ColorUnknown = "unknown"
|
||||
|
||||
AlertLevelExtraRed = 1
|
||||
AlertLevelRed = 2
|
||||
AlertLevelYellow = 3
|
||||
|
||||
OneDayName = "单日"
|
||||
OneWeekDayName = "七日"
|
||||
OneMonthDayName = "三十日"
|
||||
YellowAlertInfo = "您的店铺-%s,由于%s%s%s%d%%,可能会被系统下线,请及时补救。"
|
||||
RedAlertInfo = "您的店铺-%s,由于%s%s%s%d%%,会被系统下线,需要马上补救。"
|
||||
ExtraRedAlertInfo = "您的店铺-%s,由于%s%s%s%d%%,会被系统下线,需要马上补救。"
|
||||
NoOrderAlertInfo = "您的店铺-%s,由于近%s无订单,会被系统下线,需要马上补救。"
|
||||
RiskOrderAlertInfo = "您的店铺-%s,可能有虚假定单,定单号为:%s,可能会被罚款,请及时与运营联系!"
|
||||
)
|
||||
|
||||
var (
|
||||
checkStoreAlertTimeList = []string{
|
||||
"18:30:00",
|
||||
}
|
||||
|
||||
AlertTypeNameMap = map[int]string{
|
||||
AlertTypePickTimeOrderDaDa: "拣货履约率(达达)",
|
||||
AlertTypeBadCommentOrder: "差评率",
|
||||
AlertTypeAbsentGoodsOrder: "缺货率",
|
||||
AlertTypeStandardFinishTimeOrderSelfDelivery: "按时履约率(商家自送)",
|
||||
AlertTypeStandardPickUpTimeOrderDaDa: "10分钟取货完成率(达达)",
|
||||
}
|
||||
|
||||
AlertTypeExtraNameMap = map[int]string{
|
||||
AlertTypePickTimeOrderDaDa: "拣货超时订单(达达)",
|
||||
AlertTypeBadCommentOrder: "差评订单",
|
||||
AlertTypeAbsentGoodsOrder: "缺货订单",
|
||||
}
|
||||
|
||||
storeAlertDataWrapper StoreAlertDataWrapper
|
||||
)
|
||||
|
||||
type StoreAlertDataWrapper struct {
|
||||
storeAlertList map[int]*model.StoreAlert
|
||||
}
|
||||
|
||||
func (s *StoreAlertDataWrapper) InitData() {
|
||||
s.storeAlertList = make(map[int]*model.StoreAlert)
|
||||
}
|
||||
|
||||
func (s *StoreAlertDataWrapper) ClearData() {
|
||||
s.storeAlertList = nil
|
||||
}
|
||||
|
||||
func (s *StoreAlertDataWrapper) IsStatusField(valueName string) bool {
|
||||
return valueName == model.FieldYellowStatus || valueName == model.FieldRedStatus || valueName == model.FieldExtraRedStatus
|
||||
}
|
||||
|
||||
func (s *StoreAlertDataWrapper) SetData(storeID int, valueName string, value int) {
|
||||
data := s.storeAlertList[storeID]
|
||||
if data == nil {
|
||||
data = &model.StoreAlert{}
|
||||
data.StoreID = storeID
|
||||
data.AlertDate = utils.GetCurDate()
|
||||
s.storeAlertList[storeID] = data
|
||||
}
|
||||
if s.IsStatusField(valueName) {
|
||||
srcFieldValue := refutil.GetObjFieldByName(data, valueName).(int)
|
||||
value |= srcFieldValue
|
||||
}
|
||||
refutil.SetObjFieldByName(data, valueName, value)
|
||||
}
|
||||
|
||||
func (s StoreAlertDataWrapper) InsertStoreAlertList() {
|
||||
for _, value := range s.storeAlertList {
|
||||
dao.InsertStoreAlert(value)
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertListToMap(listData []*model.StoreCount) (mapData map[int]int) {
|
||||
mapData = make(map[int]int)
|
||||
for _, value := range listData {
|
||||
mapData[value.StoreID] = value.Count
|
||||
}
|
||||
|
||||
return mapData
|
||||
}
|
||||
|
||||
func ConvertListToMapEx(listData []*model.StoreOrder) (mapData map[int][]string) {
|
||||
mapData = make(map[int][]string)
|
||||
for _, value := range listData {
|
||||
if mapData[value.StoreID] == nil {
|
||||
mapData[value.StoreID] = []string{}
|
||||
}
|
||||
mapData[value.StoreID] = append(mapData[value.StoreID], value.VendorOrderID)
|
||||
}
|
||||
|
||||
return mapData
|
||||
}
|
||||
|
||||
func GetAlertInfo(dayNum, alertLevel int, storeName string, alertType int, logicCondition string, value int) (info string) {
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
if alertLevel == AlertLevelExtraRed {
|
||||
info = fmt.Sprintf(ExtraRedAlertInfo, storeName, OneDayName, AlertTypeExtraNameMap[alertType], logicCondition, value)
|
||||
} else if alertLevel == AlertLevelRed {
|
||||
info = fmt.Sprintf(RedAlertInfo, storeName, OneDayName, AlertTypeNameMap[alertType], logicCondition, value)
|
||||
} else if alertLevel == AlertLevelYellow {
|
||||
info = fmt.Sprintf(YellowAlertInfo, storeName, OneDayName, AlertTypeNameMap[alertType], logicCondition, value)
|
||||
}
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
if alertLevel == AlertLevelExtraRed {
|
||||
info = fmt.Sprintf(ExtraRedAlertInfo, storeName, OneWeekDayName, AlertTypeExtraNameMap[alertType], logicCondition, value)
|
||||
} else if alertLevel == AlertLevelRed {
|
||||
info = fmt.Sprintf(RedAlertInfo, storeName, OneWeekDayName, AlertTypeNameMap[alertType], logicCondition, value)
|
||||
} else if alertLevel == AlertLevelYellow {
|
||||
info = fmt.Sprintf(YellowAlertInfo, storeName, OneWeekDayName, AlertTypeNameMap[alertType], logicCondition, value)
|
||||
}
|
||||
} else if dayNum == CheckStoreAlertOneMonthDayNum {
|
||||
info = fmt.Sprintf(NoOrderAlertInfo, storeName, OneMonthDayName)
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func CheckAlert(alertType int, dayNum int, ratio int, count int) (alertLevel int, logicCondtion string, outValue int) {
|
||||
yellowRatio := -1
|
||||
redRatio := -1
|
||||
extraCount := -1
|
||||
conditionLessEqual := false
|
||||
|
||||
switch alertType {
|
||||
case AlertTypePickTimeOrderDaDa:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
redRatio = 0
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
yellowRatio = 70
|
||||
redRatio = 50
|
||||
extraCount = 5
|
||||
}
|
||||
conditionLessEqual = true
|
||||
case AlertTypeBadCommentOrder:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
redRatio = 100
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
yellowRatio = 1
|
||||
redRatio = 3
|
||||
extraCount = 5
|
||||
}
|
||||
conditionLessEqual = false
|
||||
case AlertTypeAbsentGoodsOrder:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
redRatio = 100
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
yellowRatio = 3
|
||||
redRatio = 5
|
||||
extraCount = 5
|
||||
}
|
||||
conditionLessEqual = false
|
||||
case AlertTypeStandardFinishTimeOrderSelfDelivery:
|
||||
yellowRatio = 85
|
||||
redRatio = 70
|
||||
conditionLessEqual = true
|
||||
case AlertTypeStandardPickUpTimeOrderDaDa:
|
||||
yellowRatio = 85
|
||||
redRatio = 70
|
||||
conditionLessEqual = true
|
||||
}
|
||||
|
||||
if conditionLessEqual {
|
||||
logicCondtion = "<="
|
||||
if extraCount != -1 && count >= extraCount {
|
||||
alertLevel = AlertLevelExtraRed
|
||||
outValue = extraCount
|
||||
} else if redRatio != -1 && ratio <= redRatio {
|
||||
alertLevel = AlertLevelRed
|
||||
outValue = redRatio
|
||||
} else if yellowRatio != -1 && ratio <= yellowRatio {
|
||||
alertLevel = AlertLevelYellow
|
||||
outValue = yellowRatio
|
||||
}
|
||||
} else {
|
||||
logicCondtion = ">="
|
||||
if extraCount != -1 && count >= extraCount {
|
||||
alertLevel = AlertLevelExtraRed
|
||||
outValue = extraCount
|
||||
} else if redRatio != -1 && ratio >= redRatio {
|
||||
alertLevel = AlertLevelRed
|
||||
outValue = redRatio
|
||||
} else if yellowRatio != -1 && ratio >= yellowRatio {
|
||||
alertLevel = AlertLevelYellow
|
||||
outValue = yellowRatio
|
||||
}
|
||||
}
|
||||
|
||||
return alertLevel, logicCondtion, outValue
|
||||
}
|
||||
|
||||
func SendAlertInfo(storeID int, storeName, alertInfo string) {
|
||||
if EnableSendStoreAlert {
|
||||
baseapi.SugarLogger.Debugf("SendAlertInfo: %d, %s", storeID, alertInfo)
|
||||
weixinmsg.NotifyStoreAlertMessage(storeID, storeName, "门店警告", alertInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func GetFieldNameByAlertType(alertType, dayNum int) (fieldName string, fieldFlag int) {
|
||||
switch alertType {
|
||||
case AlertTypePickTimeOrderDaDa:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
fieldName = model.FieldPickTimeDaDa
|
||||
fieldFlag = model.FlagPickTimeDaDa
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
fieldName = model.FieldPickTimeDaDaOneWeek
|
||||
fieldFlag = model.FlagPickTimeDaDaOneWeek
|
||||
}
|
||||
case AlertTypeBadCommentOrder:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
fieldName = model.FieldBadComment
|
||||
fieldFlag = model.FlagBadComment
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
fieldName = model.FieldBadCommentOneWeek
|
||||
fieldFlag = model.FlagBadCommentOneWeek
|
||||
}
|
||||
case AlertTypeAbsentGoodsOrder:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
fieldName = model.FieldAbsentGoods
|
||||
fieldFlag = model.FlagAbsentGoods
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
fieldName = model.FieldAbsentGoodsOneWeek
|
||||
fieldFlag = model.FlagAbsentGoodsOneWeek
|
||||
}
|
||||
case AlertTypeStandardFinishTimeOrderSelfDelivery:
|
||||
fieldName = model.FieldStandardFinishTimeSelfDelivery
|
||||
fieldFlag = model.FlagStandardFinishTimeSelfDelivery
|
||||
case AlertTypeStandardPickUpTimeOrderDaDa:
|
||||
fieldName = model.FieldStandardPickUpTimeDaDa
|
||||
fieldFlag = model.FlagStandardPickUpTimeDaDa
|
||||
}
|
||||
|
||||
return fieldName, fieldFlag
|
||||
}
|
||||
|
||||
func SendAlertInfoWrapper(storeID int, storeName string, dayNum, alertType, count, totalCount int) {
|
||||
if totalCount > 0 {
|
||||
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
|
||||
alertLevel, logicCondtion, outValue := CheckAlert(alertType, dayNum, ratio, count)
|
||||
if alertLevel != 0 {
|
||||
alertInfo := GetAlertInfo(dayNum, alertLevel, storeName, alertType, logicCondtion, outValue)
|
||||
SendAlertInfo(storeID, storeName, alertInfo)
|
||||
fieldName, fieldFlag := GetFieldNameByAlertType(alertType, dayNum)
|
||||
storeAlertDataWrapper.SetData(storeID, fieldName, ratio)
|
||||
|
||||
if alertLevel == AlertLevelExtraRed {
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldExtraRedStatus, fieldFlag)
|
||||
} else if alertLevel == AlertLevelRed {
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, fieldFlag)
|
||||
} else if alertLevel == AlertLevelYellow {
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldYellowStatus, fieldFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CheckStoreDayAlert(storeList []*cms.StoreExt, dayNum int) {
|
||||
db := dao.GetDB()
|
||||
//拣货履约订单(达达)
|
||||
pickTimeOrderCountDaDaList, _ := dao.GetStandardPickTimeOrderCountByDaDa(db, dayNum, IncludeToday)
|
||||
pickTimeOrderCountDaDaMapData := ConvertListToMap(pickTimeOrderCountDaDaList)
|
||||
|
||||
//完成订单(达达)
|
||||
finishOrderCountDaDaList, _ := dao.GetFinishOrderCountByDaDa(db, dayNum, IncludeToday)
|
||||
finishOrderCountDaDaMapData := ConvertListToMap(finishOrderCountDaDaList)
|
||||
|
||||
//差评订单
|
||||
badCommentOrderCountList, _ := dao.GetBadCommentOrderCountByDayNum(db, dayNum, IncludeToday)
|
||||
badCommentOrderCountMapData := ConvertListToMap(badCommentOrderCountList)
|
||||
|
||||
//缺货订单
|
||||
absentGoodsOrderCountList, _ := dao.GetAbsentGoodsOrderCountByDayNum(db, dayNum, IncludeToday)
|
||||
absentGoodsOrderCountMapData := ConvertListToMap(absentGoodsOrderCountList)
|
||||
|
||||
//完成订单
|
||||
finishOrderCountList, _ := dao.GetFinishOrderCountByDayNum(db, dayNum, IncludeToday)
|
||||
finishOrderCountMapData := ConvertListToMap(finishOrderCountList)
|
||||
|
||||
var standardFinishTimeOrderCountSelfDeliveryList []*model.StoreCount
|
||||
var standardFinishTimeOrderCountSelfDeliveryMapData map[int]int
|
||||
var finishOrderCountSelfDeliveryList []*model.StoreCount
|
||||
var finishOrderCountSelfDeliveryMapData map[int]int
|
||||
var standardPickUpTimeOrderCountDaDaList []*model.StoreCount
|
||||
var standardPickUpTimeOrderCountDaDaMapData map[int]int
|
||||
isOneWeekDay := dayNum == CheckStoreAlertOneWeekDayNum
|
||||
if isOneWeekDay {
|
||||
//按时履约订单(商家自送)
|
||||
standardFinishTimeOrderCountSelfDeliveryList, _ = dao.GetStandardFinishTimeOrderCountBySelfDelivery(db, dayNum, IncludeToday)
|
||||
standardFinishTimeOrderCountSelfDeliveryMapData = ConvertListToMap(standardFinishTimeOrderCountSelfDeliveryList)
|
||||
|
||||
//完成订单(商家自送)
|
||||
finishOrderCountSelfDeliveryList, _ = dao.GetFinishOrderCountBySelfDelivery(db, dayNum, IncludeToday)
|
||||
finishOrderCountSelfDeliveryMapData = ConvertListToMap(finishOrderCountSelfDeliveryList)
|
||||
|
||||
//10分钟取货完成订单(达达)
|
||||
standardPickUpTimeOrderCountDaDaList, _ = dao.GetStandardPickUpTimeOrderCountByDaDa(db, dayNum, IncludeToday)
|
||||
standardPickUpTimeOrderCountDaDaMapData = ConvertListToMap(standardPickUpTimeOrderCountDaDaList)
|
||||
}
|
||||
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeName := storeInfo.Name
|
||||
count := pickTimeOrderCountDaDaMapData[storeID]
|
||||
totalCount := finishOrderCountDaDaMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypePickTimeOrderDaDa, count, totalCount)
|
||||
|
||||
count = badCommentOrderCountMapData[storeID]
|
||||
totalCount = finishOrderCountMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeBadCommentOrder, count, totalCount)
|
||||
count = absentGoodsOrderCountMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeAbsentGoodsOrder, count, totalCount)
|
||||
|
||||
if isOneWeekDay {
|
||||
count = standardFinishTimeOrderCountSelfDeliveryMapData[storeID]
|
||||
totalCount = finishOrderCountSelfDeliveryMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeStandardFinishTimeOrderSelfDelivery, count, totalCount)
|
||||
|
||||
count = standardPickUpTimeOrderCountDaDaMapData[storeID]
|
||||
totalCount = finishOrderCountDaDaMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeStandardPickUpTimeOrderDaDa, count, totalCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CheckStoreMonthAlert(storeList []*cms.StoreExt) {
|
||||
db := dao.GetDB()
|
||||
storeCountList, _ := dao.GetFinishOrderCountByDayNum(db, CheckStoreAlertOneMonthDayNum, IncludeToday)
|
||||
storeCountMapData := make(map[int]int)
|
||||
for _, value := range storeCountList {
|
||||
storeCountMapData[value.StoreID] = value.Count
|
||||
}
|
||||
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeName := storeInfo.Name
|
||||
if _, ok := storeCountMapData[storeID]; !ok {
|
||||
alertInfo := GetAlertInfo(CheckStoreAlertOneMonthDayNum, AlertLevelRed, storeName, -1, "", -1)
|
||||
SendAlertInfo(storeID, storeName, alertInfo)
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldNoOrderInMonth, 1)
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, model.FlagNoOrderInMonth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CheckStoreRiskOrderAlert(storeList []*cms.StoreExt, dayNum int) {
|
||||
db := dao.GetDB()
|
||||
storeOrderList, _ := dao.GetRiskOrderCount(db, dayNum, IncludeToday)
|
||||
storeOrderMapData := ConvertListToMapEx(storeOrderList)
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeName := storeInfo.Name
|
||||
vendorOrderIDList := storeOrderMapData[storeID]
|
||||
if vendorOrderIDList != nil {
|
||||
vendorOrderIDStr := ""
|
||||
for index, vendorOrderID := range vendorOrderIDList {
|
||||
if index == 0 {
|
||||
vendorOrderIDStr += vendorOrderID
|
||||
} else {
|
||||
vendorOrderIDStr += "," + vendorOrderID
|
||||
}
|
||||
}
|
||||
alertInfo := fmt.Sprintf(RiskOrderAlertInfo, storeName, vendorOrderIDStr)
|
||||
SendAlertInfo(storeID, storeName, alertInfo)
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldRiskOrderCount, len(vendorOrderIDList))
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, model.FlagRiskOrderCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetWeekDay() int {
|
||||
return int(time.Now().Weekday())
|
||||
}
|
||||
|
||||
func CheckStoreAlert(ctx *jxcontext.Context, storeIDList []int) {
|
||||
storeAlertDataWrapper.InitData()
|
||||
storeList, _ := GetStoreList(ctx)
|
||||
storeIDMap := jxutils.IntList2Map(storeIDList)
|
||||
storeList = GetFilterStoreListEx(storeList, storeIDMap)
|
||||
if GetWeekDay() == MonthCheckOnWeekDay {
|
||||
CheckStoreMonthAlert(storeList)
|
||||
}
|
||||
CheckStoreDayAlert(storeList, CheckStoreAlertOneDayNum)
|
||||
CheckStoreDayAlert(storeList, CheckStoreAlertOneWeekDayNum)
|
||||
CheckStoreRiskOrderAlert(storeList, CheckStoreAlertOneDayNum)
|
||||
storeAlertDataWrapper.InsertStoreAlertList()
|
||||
storeAlertDataWrapper.ClearData()
|
||||
}
|
||||
|
||||
func ScheduleCheckStoreAlert() {
|
||||
if EnableCheckStoreAlert {
|
||||
ScheduleTimerFunc("ScheduleCheckStoreAlert", func() {
|
||||
CheckStoreAlert(jxcontext.AdminCtx, nil)
|
||||
}, checkStoreAlertTimeList)
|
||||
}
|
||||
}
|
||||
|
||||
func GetValueColorByStatus(extraRedStatus, redStatus, yellowStatus, flag int) (color string) {
|
||||
if (extraRedStatus&flag != 0) || (redStatus&flag != 0) {
|
||||
color = ColorRed
|
||||
} else if yellowStatus&flag != 0 {
|
||||
color = ColorYellow
|
||||
} else {
|
||||
color = ColorUnknown
|
||||
}
|
||||
|
||||
return color
|
||||
}
|
||||
|
||||
func GetStoreAlertList(storeIDList []int, cityCode int, keyWord string, dateTime time.Time, offset, pageSize int) (storeAlertData model.StoreAlertData, err error) {
|
||||
db := dao.GetDB()
|
||||
storeAlertList, err := dao.GetStoreAlertList(db, storeIDList, cityCode, keyWord, dateTime)
|
||||
if err == nil && len(storeAlertList) > 0 {
|
||||
offset = jxutils.FormalizePageOffset(offset)
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
var pagedStoreAlertList []*model.StoreAlertEx
|
||||
for i := offset; i < offset+pageSize && i < len(storeAlertList); i++ {
|
||||
pagedStoreAlertList = append(pagedStoreAlertList, storeAlertList[i])
|
||||
}
|
||||
|
||||
var storeAlertAdvancedList []*model.StoreAlertAdvanced
|
||||
for _, value := range pagedStoreAlertList {
|
||||
storeAlertAdvanced := &model.StoreAlertAdvanced{}
|
||||
storeAlertAdvanced.ID = value.ID
|
||||
storeAlertAdvanced.CreatedTime = value.CreatedTime
|
||||
storeAlertAdvanced.AlertDate = value.AlertDate
|
||||
storeAlertAdvanced.StoreID = value.StoreID
|
||||
storeAlertAdvanced.StoreName = value.StoreName
|
||||
storeAlertAdvanced.CityName = value.CityName
|
||||
|
||||
storeAlertAdvanced.PickTimeDaDa.Value = fmt.Sprintf("%d%%", value.PickTimeDaDa)
|
||||
storeAlertAdvanced.PickTimeDaDa.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagPickTimeDaDa)
|
||||
|
||||
storeAlertAdvanced.BadComment.Value = fmt.Sprintf("%d%%", value.BadComment)
|
||||
storeAlertAdvanced.BadComment.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagBadComment)
|
||||
|
||||
storeAlertAdvanced.AbsentGoods.Value = fmt.Sprintf("%d%%", value.AbsentGoods)
|
||||
storeAlertAdvanced.AbsentGoods.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagAbsentGoods)
|
||||
|
||||
storeAlertAdvanced.PickTimeDaDaOneWeek.Value = fmt.Sprintf("%d%%", value.PickTimeDaDaOneWeek)
|
||||
storeAlertAdvanced.PickTimeDaDaOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagPickTimeDaDaOneWeek)
|
||||
|
||||
storeAlertAdvanced.BadCommentOneWeek.Value = fmt.Sprintf("%d%%", value.BadCommentOneWeek)
|
||||
storeAlertAdvanced.BadCommentOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagBadCommentOneWeek)
|
||||
|
||||
storeAlertAdvanced.AbsentGoodsOneWeek.Value = fmt.Sprintf("%d%%", value.AbsentGoodsOneWeek)
|
||||
storeAlertAdvanced.AbsentGoodsOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagAbsentGoodsOneWeek)
|
||||
|
||||
storeAlertAdvanced.StandardFinishTimeSelfDelivery.Value = fmt.Sprintf("%d%%", value.StandardFinishTimeSelfDelivery)
|
||||
storeAlertAdvanced.StandardFinishTimeSelfDelivery.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagStandardFinishTimeSelfDelivery)
|
||||
|
||||
storeAlertAdvanced.StandardPickUpTimeDaDa.Value = fmt.Sprintf("%d%%", value.StandardPickUpTimeDaDa)
|
||||
storeAlertAdvanced.StandardPickUpTimeDaDa.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagStandardPickUpTimeDaDa)
|
||||
|
||||
if value.NoOrderInMonth == 1 {
|
||||
storeAlertAdvanced.NoOrderInMonth.Value = "是"
|
||||
} else {
|
||||
storeAlertAdvanced.NoOrderInMonth.Value = "否"
|
||||
}
|
||||
storeAlertAdvanced.NoOrderInMonth.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagNoOrderInMonth)
|
||||
|
||||
storeAlertAdvanced.RiskOrderCount.Value = utils.Int2Str(value.RiskOrderCount)
|
||||
storeAlertAdvanced.RiskOrderCount.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagRiskOrderCount)
|
||||
|
||||
storeAlertAdvancedList = append(storeAlertAdvancedList, storeAlertAdvanced)
|
||||
}
|
||||
storeAlertData.TotalCount = len(storeAlertList)
|
||||
storeAlertData.StoreAlertList = storeAlertAdvancedList
|
||||
}
|
||||
|
||||
return storeAlertData, err
|
||||
}
|
||||
@@ -1,882 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/refutil"
|
||||
)
|
||||
|
||||
const (
|
||||
EnableScheduleScoreStore = true
|
||||
ParallelCount = 1
|
||||
|
||||
GoldMedalScore = 90
|
||||
SilverMedalScore = 80
|
||||
BronzeMedalScore = 70
|
||||
GoldMedalLevel = 1
|
||||
SilverMedalLevel = 2
|
||||
BronzeMedalLevel = 3
|
||||
|
||||
ItemTotalScore = 10
|
||||
|
||||
StoreOpenTimeNormalTime = 12.0 //小时
|
||||
SaleSkuNormalCount = 1000 //数量
|
||||
SaleSkuScorePerUnit = float64(ItemTotalScore) / SaleSkuNormalCount //分数
|
||||
PromotionSkuNormalCount = 20 //数量
|
||||
AveragePickupTimeNormalTime = 10.0 //分钟
|
||||
BadCommentOrderNormalRatio = 0.2 //百分比
|
||||
UnfinishOrderNormalRatio = 1.0 //百分比
|
||||
AbsentGoodsOrderNormalRatio = 1.0 //百分比
|
||||
StoreRangeGoodRadius = 2.0 //千米
|
||||
StoreRangeBadRadius = 1.0 //千米
|
||||
SaleSkuPriceRatio = 90 //千米
|
||||
SaleSkuCheckRange = 5.0 //千米
|
||||
|
||||
WeekNum = 5 //得到门店近期周的数量
|
||||
)
|
||||
|
||||
var (
|
||||
scoreStoreTimeList = []string{
|
||||
"23:00:00",
|
||||
}
|
||||
scoreStoreCheckTimeEnd = "23:30:00"
|
||||
fullVendorList = map[int]bool{
|
||||
model.VendorIDJD: true,
|
||||
model.VendorIDMTWM: true,
|
||||
model.VendorIDEBAI: true,
|
||||
}
|
||||
storeScoreFieldName = []string{
|
||||
model.FieldStoreOpenTime,
|
||||
model.FieldSaleSkuCount,
|
||||
model.FieldAveragePickupTime,
|
||||
model.FieldBadCommentOrder,
|
||||
model.FieldUnfinishOrder,
|
||||
model.FieldAbsentGoodsOrder,
|
||||
model.FieldPromotionSku,
|
||||
model.FieldFullVendor,
|
||||
model.FieldStoreRange,
|
||||
model.FieldSaleSkuPrice,
|
||||
}
|
||||
|
||||
storeScoreDataWrapper StoreScoreDataWrapper
|
||||
allStoreSkusWrapper AllStoreSkusWrapper
|
||||
scoreDate time.Time
|
||||
isScoring bool
|
||||
)
|
||||
|
||||
type AllStoreSkusWrapper struct {
|
||||
allStoreSkus map[int]map[int]int
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) InitData() {
|
||||
a.allStoreSkus = make(map[int]map[int]int)
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) ClearData() {
|
||||
a.allStoreSkus = nil
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) SetData(storeID int, skuMapData map[int]int) {
|
||||
a.locker.Lock()
|
||||
defer a.locker.Unlock()
|
||||
a.allStoreSkus[storeID] = skuMapData
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) GetData(storeID int) map[int]int {
|
||||
a.locker.RLock()
|
||||
defer a.locker.RUnlock()
|
||||
return a.allStoreSkus[storeID]
|
||||
}
|
||||
|
||||
type StoreScoreDataWrapper struct {
|
||||
storeScoreData map[int]*model.StoreScore
|
||||
dailyBadCommentOrderCount map[int]int
|
||||
dailyUnFinishOrderCount map[int]int
|
||||
dailyFinishOrderCount map[int]int
|
||||
dailyAbsentGoodsOrderCount map[int]int
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) InitData() {
|
||||
s.storeScoreData = make(map[int]*model.StoreScore)
|
||||
s.dailyBadCommentOrderCount = make(map[int]int)
|
||||
s.dailyUnFinishOrderCount = make(map[int]int)
|
||||
s.dailyFinishOrderCount = make(map[int]int)
|
||||
s.dailyAbsentGoodsOrderCount = make(map[int]int)
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) ClearData() {
|
||||
s.storeScoreData = nil
|
||||
s.dailyBadCommentOrderCount = nil
|
||||
s.dailyUnFinishOrderCount = nil
|
||||
s.dailyFinishOrderCount = nil
|
||||
s.dailyAbsentGoodsOrderCount = nil
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetData(storeID int, valueName string, value int) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
data := s.storeScoreData[storeID]
|
||||
if data == nil {
|
||||
data = &model.StoreScore{}
|
||||
data.StoreID = storeID
|
||||
data.ScoreDate = scoreDate
|
||||
s.storeScoreData[storeID] = data
|
||||
}
|
||||
valueInfo := reflect.ValueOf(data).Elem()
|
||||
valueInfo.FieldByName(valueName).SetInt(int64(value))
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyBadCommentOrderCount(storeCountList []*model.StoreCount) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
for _, value := range storeCountList {
|
||||
s.dailyBadCommentOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyBadCommentOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyBadCommentOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyUnFinishOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyUnFinishOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyUnFinishOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyUnFinishOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyFinishOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyFinishOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyFinishOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyFinishOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyAbsentGoodsOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyAbsentGoodsOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyAbsentGoodsOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyAbsentGoodsOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) InsertStoreScore() {
|
||||
for _, value := range s.storeScoreData {
|
||||
dao.InsertStoreScore(value)
|
||||
}
|
||||
}
|
||||
|
||||
//得到所有门店的可售商品(优化内存,只存商品的价格)
|
||||
func GetAllStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeList []*cms.StoreExt) {
|
||||
allStoreSkusWrapper.InitData()
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeInfo := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeInfo.ID
|
||||
if jxSkuInfoData, err2 := cms.GetStoreSkus(ctx, storeID, []int{}, true, "", true, false, map[string]interface{}{}, 0, -1); jxSkuInfoData != nil {
|
||||
jxSkuPriceMapData := make(map[int]int)
|
||||
for _, value := range jxSkuInfoData.SkuNames {
|
||||
for _, skuInfo := range value.Skus {
|
||||
saleStatus := jxutils.MergeSkuStatus(skuInfo.SkuStatus, skuInfo.StoreSkuStatus)
|
||||
if saleStatus == model.SkuStatusNormal {
|
||||
jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
allStoreSkusWrapper.SetData(storeID, jxSkuPriceMapData)
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("store_score.GetAllStoreSkus %d return empty, err:%v", storeID, err2)
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
taskParallel := tasksch.NewParallelTask("得到所有门店商品", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList)
|
||||
tasksch.HandleTask(taskParallel, parentTask, true).Run()
|
||||
taskParallel.GetResult(0)
|
||||
}
|
||||
|
||||
func GetOpenTime(opTimeList []int16) (opTime float64) {
|
||||
opTime = 0
|
||||
for index, _ := range opTimeList {
|
||||
if index%2 == 1 {
|
||||
endTime := opTimeList[index]
|
||||
startTime := opTimeList[index-1]
|
||||
diffHour := float64(endTime/100 - startTime/100)
|
||||
diffMin := float64(endTime%100-startTime%100) / 60
|
||||
opTime += diffHour + diffMin
|
||||
}
|
||||
}
|
||||
return opTime
|
||||
}
|
||||
|
||||
//营业时间12小时及以上满分,总分10分,每少一个小时扣1分
|
||||
func ScoreStoreOpenTime(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
storeStatus := storeInfo.Status
|
||||
isStoreOpen := storeStatus == model.StoreStatusOpened
|
||||
finalScore := 0
|
||||
if isStoreOpen {
|
||||
for _, storeMap := range storeInfo.StoreMaps {
|
||||
isSyncStoreSku := storeMap.IsSync
|
||||
vendorStoreStatus := storeMap.Status
|
||||
isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 {
|
||||
opTime := GetOpenTime(opTimeList)
|
||||
if opTime >= StoreOpenTimeNormalTime {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round(StoreOpenTimeNormalTime - opTime))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldStoreOpenTime, finalScore)
|
||||
}
|
||||
|
||||
//可售商品数量大于1000,总分10分,按比例扣
|
||||
func ScoreSaleSkuCount(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
skusMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
finalScore := 0
|
||||
if len(skusMapData) > 0 {
|
||||
saleSkuCount := len(skusMapData)
|
||||
finalScore = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit))
|
||||
if finalScore > ItemTotalScore {
|
||||
finalScore = ItemTotalScore
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuCount, finalScore)
|
||||
}
|
||||
|
||||
//平均捡货时间小于等于拣货截止时间为10分满分,每超出1分钟,减1分
|
||||
func ScoreAveragePickupTime(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
db := dao.GetDB()
|
||||
orderList, err := dao.GetDailyFinishOrderList(db, storeID, scoreDate)
|
||||
orderListCount := len(orderList)
|
||||
finalScore := 0
|
||||
if err == nil && orderListCount > 0 {
|
||||
totalScore := 0
|
||||
for _, value := range orderList {
|
||||
statusTime := value.StatusTime.Unix()
|
||||
pickDeadline := value.PickDeadline.Unix()
|
||||
if statusTime <= pickDeadline {
|
||||
totalScore += ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round(float64(statusTime-pickDeadline) / 60))
|
||||
tempScore := ItemTotalScore - decScore
|
||||
if tempScore < 0 {
|
||||
tempScore = 0
|
||||
}
|
||||
totalScore += tempScore
|
||||
}
|
||||
}
|
||||
finalScore = totalScore / orderListCount
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldAveragePickupTime, finalScore)
|
||||
}
|
||||
|
||||
//差评订单和完成订单比例小于0.2%,得满分10分,每增加0.1%减1分
|
||||
func ScoreBadCommentOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
badCommentOrderCount := storeScoreDataWrapper.GetDailyBadCommentOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
badCommentOrderRatio := float64(badCommentOrderCount) * 100 / float64(finishOrderCount)
|
||||
if badCommentOrderRatio <= BadCommentOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((badCommentOrderRatio - BadCommentOrderNormalRatio) / 0.1))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldBadCommentOrder, finalScore)
|
||||
}
|
||||
|
||||
//未完成订单和完成订单比小于1%,得满分10分,比例每增加5%,分数减1
|
||||
func ScoreUnfinishOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
unFinishOrderCount := storeScoreDataWrapper.GetDailyUnFinishOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
unfinishOrderRatio := float64(unFinishOrderCount) * 100 / float64(finishOrderCount)
|
||||
if unfinishOrderRatio <= UnfinishOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((unfinishOrderRatio - UnfinishOrderNormalRatio) / 5))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldUnfinishOrder, finalScore)
|
||||
}
|
||||
|
||||
//缺货订单和完成订单比小于1%得10分,比例每增加0.1%减1分
|
||||
func ScoreAbsentGoodsOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
absentGoodsOrderCount := storeScoreDataWrapper.GetDailyAbsentGoodsOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
absentGoodsOrderRatio := float64(absentGoodsOrderCount) * 100 / float64(finishOrderCount)
|
||||
if absentGoodsOrderRatio <= AbsentGoodsOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((absentGoodsOrderRatio - AbsentGoodsOrderNormalRatio) / 0.1))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldAbsentGoodsOrder, finalScore)
|
||||
}
|
||||
|
||||
//促销品数量20个以上为满分10分,每少2个扣1分
|
||||
func ScorePromotionSku(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
db := dao.GetDB()
|
||||
beginTime := time.Now()
|
||||
endTime := time.Now()
|
||||
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, -1, nil, model.ActTypeAll, []int{storeID}, nil, beginTime, endTime)
|
||||
finalScore := 0
|
||||
if err == nil && len(actStoreSkuList) > 0 {
|
||||
actStoreSkuMap := make(map[int]int)
|
||||
for _, value := range actStoreSkuList {
|
||||
if value.Type != model.ActSkuFake {
|
||||
actStoreSkuMap[value.SkuID] = 1
|
||||
}
|
||||
}
|
||||
promotionSkuCount := len(actStoreSkuMap)
|
||||
if promotionSkuCount >= PromotionSkuNormalCount {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (PromotionSkuNormalCount - promotionSkuCount) / 2
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldPromotionSku, finalScore)
|
||||
}
|
||||
|
||||
//经营全平台满分10分,每少一个平台扣2分(一个平台没有得0分)
|
||||
func ScoreFullVendor(storeInfo *cms.StoreExt) {
|
||||
fullVendorCount := len(fullVendorList)
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
storeStatus := storeInfo.Status
|
||||
isStoreOpen := storeStatus == model.StoreStatusOpened
|
||||
count := 0
|
||||
for _, storeMap := range storeInfo.StoreMaps {
|
||||
isSyncStoreSku := storeMap.IsSync
|
||||
vendorStoreStatus := storeMap.Status
|
||||
isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count > 0 {
|
||||
if count == fullVendorCount {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (fullVendorCount - count) * 2
|
||||
finalScore = ItemTotalScore - decScore
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldFullVendor, finalScore)
|
||||
}
|
||||
|
||||
//经营范围面积大于半径2km的圆得满分10分,低于1km得分0
|
||||
func ScoreStoreRange(storeInfo *cms.StoreExt) {
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
if storeInfo.DeliveryRangeType == model.DeliveryRangeTypePolygon {
|
||||
if storeInfo.DeliveryRange != "" {
|
||||
points := jxutils.CoordinateStr2Points(storeInfo.DeliveryRange)
|
||||
area := jxutils.CalcPolygonAreaAutonavi(points)
|
||||
goodArea := math.Pi * StoreRangeGoodRadius * StoreRangeGoodRadius
|
||||
badArea := math.Pi * StoreRangeBadRadius * StoreRangeBadRadius
|
||||
if area >= goodArea {
|
||||
finalScore = ItemTotalScore
|
||||
} else if area <= badArea {
|
||||
finalScore = 0
|
||||
} else {
|
||||
diff := goodArea - area
|
||||
ratio := float64(ItemTotalScore) / (goodArea - badArea)
|
||||
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
|
||||
}
|
||||
}
|
||||
} else if storeInfo.DeliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
deliveryRadius := utils.Str2Float64WithDefault(storeInfo.DeliveryRange, 0) / 1000
|
||||
if deliveryRadius >= StoreRangeGoodRadius {
|
||||
finalScore = ItemTotalScore
|
||||
} else if deliveryRadius <= StoreRangeBadRadius {
|
||||
finalScore = 0
|
||||
} else {
|
||||
diff := StoreRangeGoodRadius - deliveryRadius
|
||||
ratio := float64(ItemTotalScore) / (StoreRangeGoodRadius - StoreRangeBadRadius)
|
||||
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
|
||||
}
|
||||
}
|
||||
if finalScore < 0 {
|
||||
globals.SugarLogger.Infof("ScoreStoreRange abnormal finalScore:%d, storeInfo:%s", finalScore, utils.Format4Output(storeInfo, true))
|
||||
finalScore = 0
|
||||
} else if finalScore > ItemTotalScore {
|
||||
globals.SugarLogger.Infof("ScoreStoreRange abnormal finalScore:%d, storeInfo:%s", finalScore, utils.Format4Output(storeInfo, true))
|
||||
finalScore = ItemTotalScore
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldStoreRange, finalScore)
|
||||
}
|
||||
|
||||
//得到距离某个门店多少KM内的所有门店信息
|
||||
func GetRangeStoreList(storeID int, lng, lat, checkRange float64, storeList []*cms.StoreExt) (outStoreList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
if storeInfo.ID == storeID {
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
} else {
|
||||
distance := jxutils.EarthDistance(lng, lat, storeInfo.FloatLng, storeInfo.FloatLat)
|
||||
if distance <= checkRange {
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
//得到给定门店列表里的同一SkuID商品的平均价格
|
||||
func GetStoreSkusAveragePrice(storeList []*cms.StoreExt) map[int]int {
|
||||
skusTotalPrice := make(map[int]int)
|
||||
skusCount := make(map[int]int)
|
||||
skusAveragePrice := make(map[int]int)
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeSkuMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
for skuID, skuPrice := range storeSkuMapData {
|
||||
skusTotalPrice[skuID] += skuPrice
|
||||
skusCount[skuID]++
|
||||
}
|
||||
}
|
||||
for id, totalPrice := range skusTotalPrice {
|
||||
skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id])))
|
||||
}
|
||||
return skusAveragePrice
|
||||
}
|
||||
|
||||
func GetSkusCountLessEqualAvgPrice(storeID int, skusAveragePrice map[int]int) (count int) {
|
||||
storeSkuMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
for skuID, skuPrice := range storeSkuMapData {
|
||||
skuAvgPrice := skusAveragePrice[skuID]
|
||||
if skuPrice <= skuAvgPrice {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
//可售商品价格在附近5km内门店比较,价格低于等于平均值的商品数占90%以上满分10分,比例每降低10%减1分,100%超标得0分
|
||||
func ScoreSaleSkuPrice(storeInfo *cms.StoreExt, storeList []*cms.StoreExt) {
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
totalCount := len(allStoreSkusWrapper.GetData(storeID))
|
||||
if totalCount > 0 {
|
||||
rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, SaleSkuCheckRange, storeList)
|
||||
skusAveragePrice := GetStoreSkusAveragePrice(rangeStoreList)
|
||||
count := GetSkusCountLessEqualAvgPrice(storeID, skusAveragePrice)
|
||||
if count > 0 {
|
||||
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
|
||||
if ratio >= SaleSkuPriceRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (SaleSkuPriceRatio - ratio) / 10
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuPrice, finalScore)
|
||||
}
|
||||
|
||||
func GetFilterStoreListEx(storeList []*cms.StoreExt, storeIDMap map[int]int) (outStoreList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
if len(storeIDMap) > 0 {
|
||||
if _, ok := storeIDMap[storeID]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
var tempStoreMaps []*model.StoreMap
|
||||
for _, vendorStoreInfo := range storeInfo.StoreMaps {
|
||||
vendorID := vendorStoreInfo.VendorID
|
||||
if _, ok := fullVendorList[vendorID]; !ok {
|
||||
continue
|
||||
}
|
||||
tempStoreMaps = append(tempStoreMaps, vendorStoreInfo)
|
||||
}
|
||||
if len(tempStoreMaps) > 0 {
|
||||
storeInfo.StoreMaps = tempStoreMaps
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{}, err error) {
|
||||
isScoring = true
|
||||
scoreDate = utils.GetCurDate()
|
||||
var storeList []*cms.StoreExt
|
||||
taskCount := 5
|
||||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step0 begin")
|
||||
storeScoreDataWrapper.InitData()
|
||||
storeList, err = GetStoreList(ctx)
|
||||
storeIDMap := jxutils.IntList2Map(storeIDList)
|
||||
storeList = GetFilterStoreListEx(storeList, storeIDMap)
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step0 end")
|
||||
case 1:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step1 begin")
|
||||
GetAllStoreSkus(ctx, task, storeList)
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step1 end")
|
||||
case 2:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step2 begin")
|
||||
db := dao.GetDB()
|
||||
storeCountList, err := dao.GetDailyBadCommentOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyBadCommentOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyBadCommentOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyUnFinishOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyUnFinishOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyUnFinishOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyFinishOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyFinishOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyFinishOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyAbsentGoodsOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyAbsentGoodsOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyAbsentGoodsOrderCount %v", err)
|
||||
}
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step2 end")
|
||||
case 3:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step3 begin")
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeInfo := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeInfo.ID
|
||||
baseapi.SugarLogger.Debugf("Begin store id:%d", storeID)
|
||||
ScoreStoreOpenTime(storeInfo)
|
||||
ScoreSaleSkuCount(storeInfo)
|
||||
ScoreAveragePickupTime(storeInfo)
|
||||
ScoreBadCommentOrder(storeInfo)
|
||||
ScoreUnfinishOrder(storeInfo)
|
||||
ScoreAbsentGoodsOrder(storeInfo)
|
||||
ScorePromotionSku(storeInfo)
|
||||
ScoreFullVendor(storeInfo)
|
||||
ScoreStoreRange(storeInfo)
|
||||
ScoreSaleSkuPrice(storeInfo, storeList)
|
||||
baseapi.SugarLogger.Debugf("End store id:%d", storeID)
|
||||
return retVal, err
|
||||
}
|
||||
taskParallel := tasksch.NewParallelTask("计算门店得分", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList)
|
||||
tasksch.HandleTask(taskParallel, task, true).Run()
|
||||
taskParallel.GetResult(0)
|
||||
_, err = taskParallel.GetResult(0)
|
||||
if err != nil {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore taskParallel error:%v", err)
|
||||
}
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step3 end")
|
||||
case 4:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step4 begin")
|
||||
storeScoreDataWrapper.InsertStoreScore()
|
||||
storeScoreDataWrapper.ClearData()
|
||||
allStoreSkusWrapper.ClearData()
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step4 end")
|
||||
isScoring = false
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
taskSeq := tasksch.NewSeqTask("门店评分-序列任务", ctx, taskSeqFunc, taskCount)
|
||||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||||
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func ScheduleScoreStore() {
|
||||
if EnableScheduleScoreStore {
|
||||
ScheduleTimerFunc("ScheduleScoreStore", func() {
|
||||
if !isScoring {
|
||||
ScoreStore(jxcontext.AdminCtx, nil)
|
||||
}
|
||||
}, scoreStoreTimeList)
|
||||
CheckScoreStore()
|
||||
}
|
||||
}
|
||||
|
||||
func CheckScoreStore() {
|
||||
if !isScoring {
|
||||
curTime := time.Now()
|
||||
checkTimeStr1 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreTimeList[0])
|
||||
checkTime1 := utils.Str2Time(checkTimeStr1)
|
||||
checkTimeStr2 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreCheckTimeEnd)
|
||||
checkTime2 := utils.Str2Time(checkTimeStr2)
|
||||
if curTime.Unix() >= checkTime1.Unix() && curTime.Unix() <= checkTime2.Unix() {
|
||||
db := dao.GetDB()
|
||||
hasStoreScoreData, err := dao.CheckHasStoreScoreData(db, curTime)
|
||||
if err == nil && !hasStoreScoreData {
|
||||
ScoreStore(jxcontext.AdminCtx, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Time2Week(t time.Time) int {
|
||||
yearDay := t.YearDay()
|
||||
yearFirstDay := t.AddDate(0, 0, -yearDay+1)
|
||||
firstDayInWeek := int(yearFirstDay.Weekday())
|
||||
|
||||
firstWeekDays := 1
|
||||
if firstDayInWeek != 0 {
|
||||
firstWeekDays = 7 - firstDayInWeek + 1
|
||||
}
|
||||
var week int
|
||||
if yearDay <= firstWeekDays {
|
||||
week = 1
|
||||
} else {
|
||||
tempWeek := (float64(yearDay) - float64(firstWeekDays)) / float64(7)
|
||||
week = int(math.Ceil(tempWeek)) + 1
|
||||
}
|
||||
|
||||
return week
|
||||
}
|
||||
|
||||
func SplitToSingleWeekDataList(storeScoreList []*model.StoreScoreEx) (weekDataList [][]*model.StoreScoreEx) {
|
||||
singleWeekData := []*model.StoreScoreEx{}
|
||||
weekIndex := 0
|
||||
for _, value := range storeScoreList {
|
||||
if weekIndex == 0 {
|
||||
weekIndex = Time2Week(value.ScoreDate)
|
||||
}
|
||||
if weekIndex == Time2Week(value.ScoreDate) {
|
||||
singleWeekData = append(singleWeekData, value)
|
||||
} else {
|
||||
weekDataList = append(weekDataList, singleWeekData)
|
||||
singleWeekData = []*model.StoreScoreEx{}
|
||||
weekIndex = 0
|
||||
singleWeekData = append(singleWeekData, value)
|
||||
}
|
||||
}
|
||||
if len(singleWeekData) > 0 {
|
||||
weekDataList = append(weekDataList, singleWeekData)
|
||||
}
|
||||
|
||||
return weekDataList
|
||||
}
|
||||
|
||||
func GetStoreScoreLevel(score int) int {
|
||||
level := 0
|
||||
if score >= GoldMedalScore {
|
||||
level = GoldMedalLevel
|
||||
} else if score >= SilverMedalScore {
|
||||
level = SilverMedalLevel
|
||||
} else if score >= BronzeMedalScore {
|
||||
level = BronzeMedalLevel
|
||||
}
|
||||
|
||||
return level
|
||||
}
|
||||
|
||||
func GetWeeklyStoreScore(storeID, weekIndexParam int) (outWeeklyStoreScoreDataList []*model.WeeklyStoreScore, err error) {
|
||||
db := dao.GetDB()
|
||||
storeScoreList, err := dao.GetWeeklyStoreScoreList(db, storeID, WeekNum)
|
||||
if err == nil && len(storeScoreList) > 0 {
|
||||
weeklyStoreScoreDataList := []*model.WeeklyStoreScore{}
|
||||
weekDataList := SplitToSingleWeekDataList(storeScoreList)
|
||||
for weekIndex, weekData := range weekDataList {
|
||||
weeklyData := &model.WeeklyStoreScore{}
|
||||
weeklyData.ID = weekIndex
|
||||
weeklyData.ItemTotalScore = ItemTotalScore
|
||||
weeklyData.StoreID = storeID
|
||||
weeklyStoreScoreDataList = append(weeklyStoreScoreDataList, weeklyData)
|
||||
weekDataCount := len(weekData)
|
||||
for dayIndex, dayData := range weekData {
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
srcFieldValue := refutil.GetObjFieldByName(dayData, fieldName).(int)
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, fieldName, destFieldValue+srcFieldValue)
|
||||
}
|
||||
if weekDataCount == 1 {
|
||||
weeklyData.BeginTime = dayData.ScoreDate
|
||||
weeklyData.EndTime = dayData.ScoreDate
|
||||
} else {
|
||||
if dayIndex == 0 {
|
||||
weeklyData.EndTime = dayData.ScoreDate
|
||||
} else if dayIndex == weekDataCount-1 {
|
||||
weeklyData.BeginTime = dayData.ScoreDate
|
||||
}
|
||||
}
|
||||
weeklyData.StoreName = dayData.StoreName
|
||||
}
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, fieldName, int(math.Round(float64(destFieldValue)/float64(weekDataCount))))
|
||||
}
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
srcFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, model.FieldTotalScore).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, model.FieldTotalScore, destFieldValue+srcFieldValue)
|
||||
}
|
||||
weeklyData.Level = GetStoreScoreLevel(weeklyData.TotalScore)
|
||||
}
|
||||
if weekIndexParam == -1 {
|
||||
outWeeklyStoreScoreDataList = weeklyStoreScoreDataList
|
||||
} else {
|
||||
fmt.Println("testss", utils.Format4Output(weeklyStoreScoreDataList, false))
|
||||
outWeeklyStoreScoreDataList = []*model.WeeklyStoreScore{weeklyStoreScoreDataList[weekIndexParam]}
|
||||
}
|
||||
}
|
||||
|
||||
return outWeeklyStoreScoreDataList, err
|
||||
}
|
||||
|
||||
func GetStoreTotalScoreList(storeIDList []int, cityCode int, keyWord string, beginTime, endTime time.Time, isDesc bool, checkScoreLow, checkScoreHigh, offset, pageSize int) (storeTotalScoreEx model.StoreTotalScoreEx, err error) {
|
||||
db := dao.GetDB()
|
||||
storeTotalScoreMapData := make(map[int]*model.StoreTotalScore)
|
||||
storeTotalScoreList, err := dao.GetStoreTotalScoreList(db, storeIDList, cityCode, keyWord, beginTime, endTime)
|
||||
var filterStoreTotalScoreList []*model.StoreTotalScore
|
||||
if err == nil && len(storeTotalScoreList) > 0 {
|
||||
countDayNum := make(map[int]int)
|
||||
for _, value := range storeTotalScoreList {
|
||||
storeID := value.StoreID
|
||||
if storeTotalScoreMapData[storeID] == nil {
|
||||
storeTotalScore := &model.StoreTotalScore{}
|
||||
storeTotalScore.StoreID = value.StoreID
|
||||
storeTotalScore.StoreName = value.StoreName
|
||||
storeTotalScore.CityName = value.CityName
|
||||
storeTotalScoreMapData[storeID] = storeTotalScore
|
||||
}
|
||||
storeTotalScore := storeTotalScoreMapData[storeID]
|
||||
storeTotalScore.StoreScore += value.StoreScore
|
||||
countDayNum[storeID]++
|
||||
}
|
||||
for storeID, value := range storeTotalScoreMapData {
|
||||
value.StoreScore = int(math.Round(float64(value.StoreScore) / float64(countDayNum[storeID])))
|
||||
needAdd := true
|
||||
if checkScoreLow > 0 && value.StoreScore < checkScoreLow {
|
||||
needAdd = false
|
||||
}
|
||||
if checkScoreHigh > 0 && value.StoreScore > checkScoreHigh {
|
||||
needAdd = false
|
||||
}
|
||||
if needAdd {
|
||||
filterStoreTotalScoreList = append(filterStoreTotalScoreList, value)
|
||||
}
|
||||
}
|
||||
if isDesc {
|
||||
sort.Slice(filterStoreTotalScoreList, func(i, j int) bool {
|
||||
data1 := filterStoreTotalScoreList[i]
|
||||
data2 := filterStoreTotalScoreList[j]
|
||||
if data1.StoreScore == data2.StoreScore {
|
||||
return data1.StoreID < data2.StoreID
|
||||
} else {
|
||||
return data1.StoreScore > data2.StoreScore
|
||||
}
|
||||
})
|
||||
} else {
|
||||
sort.Slice(filterStoreTotalScoreList, func(i, j int) bool {
|
||||
data1 := filterStoreTotalScoreList[i]
|
||||
data2 := filterStoreTotalScoreList[j]
|
||||
if data1.StoreScore == data2.StoreScore {
|
||||
return data1.StoreID < data2.StoreID
|
||||
} else {
|
||||
return data1.StoreScore < data2.StoreScore
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
offset = jxutils.FormalizePageOffset(offset)
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
var pagedStoreTotalScoreList []*model.StoreTotalScore
|
||||
for i := offset; i < offset+pageSize && i < len(filterStoreTotalScoreList); i++ {
|
||||
pagedStoreTotalScoreList = append(pagedStoreTotalScoreList, filterStoreTotalScoreList[i])
|
||||
}
|
||||
|
||||
storeTotalScoreEx.TotalCount = len(filterStoreTotalScoreList)
|
||||
storeTotalScoreEx.StoreTotalScoreList = pagedStoreTotalScoreList
|
||||
|
||||
return storeTotalScoreEx, err
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestScoreStore(t *testing.T) {
|
||||
ScoreStore(jxcontext.AdminCtx, []int{})
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
const (
|
||||
DayNum = 30 //请求天数
|
||||
LimitNum = 100 //最大数据限制
|
||||
)
|
||||
|
||||
func GetStoreSkuSalesInfo(ctx *jxcontext.Context, storeID int) (outStoreSkuSales []*model.StoreSkuSales, err error) {
|
||||
db := dao.GetDB()
|
||||
//得到所有门店
|
||||
storeList, err := GetStoreList(ctx)
|
||||
if err == nil {
|
||||
storeList = GetFilterStoreListEx(storeList, nil)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
storeMapData := make(map[int]*cms.StoreExt)
|
||||
for _, value := range storeList {
|
||||
storeMapData[value.ID] = value
|
||||
}
|
||||
curStoreInfo := storeMapData[storeID]
|
||||
if curStoreInfo == nil {
|
||||
return nil, errors.New(fmt.Sprintf("未找到商店:[%d]", storeID))
|
||||
}
|
||||
cityCode := curStoreInfo.CityCode
|
||||
|
||||
//获取本市商品总销量
|
||||
citySkuSalesCntMap := make(map[int]int)
|
||||
citySkuSalesCntList, err := dao.GetSkuSalesCntList(db, -1, cityCode, DayNum, LimitNum, nil)
|
||||
citySkuIDs := []int{}
|
||||
if err == nil {
|
||||
for _, value := range citySkuSalesCntList {
|
||||
citySkuSalesCntMap[value.SkuID] = value.Count
|
||||
citySkuIDs = append(citySkuIDs, value.SkuID)
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//获取本店商品总销量
|
||||
storeSkuSalesCntMap := make(map[int]int)
|
||||
storeSkuSalesCntList, err := dao.GetSkuSalesCntList(db, storeID, cityCode, DayNum, -1, citySkuIDs)
|
||||
if err == nil {
|
||||
for _, value := range storeSkuSalesCntList {
|
||||
storeSkuSalesCntMap[value.SkuID] = value.Count
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//获取本店商品差评数量
|
||||
storeSkuBadCommentCntMap := make(map[int]int)
|
||||
storeSkuBadCommentCntList, err := dao.GetSkuBadCommentCntList(db, storeID, DayNum)
|
||||
if err == nil {
|
||||
for _, value := range storeSkuBadCommentCntList {
|
||||
storeSkuBadCommentCntMap[value.SkuID] = value.Count
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//得到当前门店商品数据
|
||||
storeSkuMapData := make(map[int]*dao.StoreSkuNameExt)
|
||||
storeSkuData, err := cms.GetStoreSkus(ctx, storeID, citySkuIDs, true, "", true, false, map[string]interface{}{}, 0, -1)
|
||||
if err == nil {
|
||||
for _, value := range storeSkuData.SkuNames {
|
||||
for _, skuInfo := range value.Skus {
|
||||
storeSkuMapData[skuInfo.SkuID] = value
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//得到5KM内的所有门店
|
||||
rangeStoreList := GetRangeStoreList(storeID, curStoreInfo.FloatLng, curStoreInfo.FloatLat, SaleSkuCheckRange, storeList)
|
||||
|
||||
//得到5KM内的所有门店的商品的价格
|
||||
allStoreSkus := make(map[int]map[int]int)
|
||||
var locker sync.RWMutex
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeInfo := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeInfo.ID
|
||||
jxSkuInfoData, err := cms.GetStoreSkus(ctx, storeID, citySkuIDs, true, "", true, false, map[string]interface{}{}, 0, -1)
|
||||
jxSkuPriceMapData := make(map[int]int)
|
||||
for _, value := range jxSkuInfoData.SkuNames {
|
||||
for _, skuInfo := range value.Skus {
|
||||
jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice
|
||||
}
|
||||
}
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
allStoreSkus[storeID] = jxSkuPriceMapData
|
||||
return retVal, err
|
||||
}
|
||||
taskParallel := tasksch.NewParallelTask("得到所有门店商品", nil, ctx, taskFunc, rangeStoreList)
|
||||
taskParallel.Run()
|
||||
_, err = taskParallel.GetResult(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//计算商品的平均价格
|
||||
skusTotalPrice := make(map[int]int)
|
||||
skusCount := make(map[int]int)
|
||||
skusAveragePrice := make(map[int]int)
|
||||
for _, storeInfo := range rangeStoreList {
|
||||
storeID := storeInfo.ID
|
||||
storeSkuMapData := allStoreSkus[storeID]
|
||||
for skuID, skuPrice := range storeSkuMapData {
|
||||
skusTotalPrice[skuID] += skuPrice
|
||||
skusCount[skuID]++
|
||||
}
|
||||
}
|
||||
for id, totalPrice := range skusTotalPrice {
|
||||
skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id])))
|
||||
}
|
||||
|
||||
//输出商品销量统计结果
|
||||
skuAndNameMapData := make(map[int]*model.SkuAndName)
|
||||
if len(storeSkuMapData) < len(citySkuIDs) {
|
||||
skuAndNameList, err := dao.GetSkus(db, citySkuIDs, nil, nil, nil, nil)
|
||||
if err == nil {
|
||||
for _, value := range skuAndNameList {
|
||||
skuAndNameMapData[value.ID] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range citySkuSalesCntList {
|
||||
skuID := value.SkuID
|
||||
storeSkuSales := &model.StoreSkuSales{}
|
||||
storeSkuSales.SkuID = skuID
|
||||
storeSkuInfo := storeSkuMapData[skuID]
|
||||
skuAndNameInfo := skuAndNameMapData[skuID]
|
||||
if storeSkuInfo != nil {
|
||||
skuName := storeSkuInfo.SkuName
|
||||
skuInfo := storeSkuInfo.Skus[0]
|
||||
storeSkuSales.SkuName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, skuInfo.Comment, skuName.Unit, skuInfo.SkuSpecQuality, skuInfo.SkuSpecUnit, 0, skuName.ExPrefix, skuName.ExPrefixBegin, skuName.ExPrefixEnd)
|
||||
storeSkuSales.SkuImage = storeSkuInfo.Img
|
||||
storeSkuSales.SkuPrice = jxutils.IntPrice2StandardCurrencyString(int64(storeSkuInfo.Skus[0].BindPrice))
|
||||
} else if skuAndNameInfo != nil {
|
||||
skuNameList, err := dao.GetSkuNames(db, []int{skuAndNameInfo.NameID}, nil, "", false)
|
||||
prefix := ""
|
||||
if err == nil && len(skuNameList) > 0 {
|
||||
storeSkuSales.SkuImage = skuNameList[0].Img
|
||||
prefix = skuNameList[0].Prefix
|
||||
}
|
||||
storeSkuSales.SkuName = jxutils.ComposeSkuName(prefix, skuAndNameInfo.Name, skuAndNameInfo.Comment, skuAndNameInfo.Unit, skuAndNameInfo.SpecQuality, skuAndNameInfo.SpecUnit, 0, skuAndNameInfo.ExPrefix, skuAndNameInfo.ExPrefixBegin, skuAndNameInfo.ExPrefixEnd)
|
||||
storeSkuSales.SkuPrice = "N/A"
|
||||
} else {
|
||||
storeSkuSales.SkuName = "N/A"
|
||||
storeSkuSales.SkuPrice = "N/A"
|
||||
}
|
||||
storeSkuSales.SkuAvgPrice = jxutils.IntPrice2StandardCurrencyString(int64(skusAveragePrice[skuID]))
|
||||
storeSkuSales.BadCommentCnt = storeSkuBadCommentCntMap[skuID]
|
||||
storeSkuSales.StoreSkuSalesCnt = storeSkuSalesCntMap[skuID]
|
||||
storeSkuSales.CitySkuSalesCnt = citySkuSalesCntMap[skuID]
|
||||
outStoreSkuSales = append(outStoreSkuSales, storeSkuSales)
|
||||
}
|
||||
|
||||
return outStoreSkuSales, err
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
type tStoreSkuBindAndSkuName struct {
|
||||
CityCode int
|
||||
StoreID int `orm:"column(store_id)"`
|
||||
NameID int `orm:"column(name_id)"`
|
||||
UnitPrice int
|
||||
UnitPriceList []int
|
||||
}
|
||||
|
||||
func GetStatisticsReportForOrders(ctx *jxcontext.Context, storeIDs []int, fromDate string, toDate string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
|
||||
db := dao.GetDB()
|
||||
fromDateParm := utils.Str2Time(fromDate)
|
||||
toDateParm := utils.Str2Time(toDate)
|
||||
//若时间间隔大于3个月则不允许查询
|
||||
if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
|
||||
return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月!: 时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||||
}
|
||||
statisticsReportForOrdersList, err = dao.GetStatisticsReportForOrders(db, storeIDs, fromDateParm, toDateParm)
|
||||
return statisticsReportForOrdersList, err
|
||||
}
|
||||
|
||||
func GetStatisticsReportForAfsOrders(ctx *jxcontext.Context, storeIDs []int, fromDate string, toDate string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
|
||||
db := dao.GetDB()
|
||||
fromDateParm := utils.Str2Time(fromDate)
|
||||
toDateParm := utils.Str2Time(toDate)
|
||||
//若时间间隔大于3个月则不允许查询
|
||||
if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
|
||||
return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月!: 时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||||
}
|
||||
statisticsReportForOrdersList, err = dao.GetGetStatisticsReportForAfsOrders(db, storeIDs, fromDateParm, toDateParm)
|
||||
return statisticsReportForOrdersList, err
|
||||
}
|
||||
|
||||
func StatisticsReportForStoreSkusPrice(ctx *jxcontext.Context, cityCodes, skuIDs []int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
var snapDateParam time.Time
|
||||
db := dao.GetDB()
|
||||
if snapDate != "" {
|
||||
snapDateParam = utils.Str2Time(snapDate)
|
||||
}
|
||||
priceReferSnapshot, totalCount, err := dao.GetPriceReferSnapshot(db, cityCodes, skuIDs, 0, snapDateParam, offset, pageSize)
|
||||
pagedInfo = &model.PagedInfo{
|
||||
Data: priceReferSnapshot,
|
||||
TotalCount: totalCount,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func BeginSavePriceRefer(ctx *jxcontext.Context, cityCodes, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
var priceReferSnapshotList []*model.PriceReferSnapshot
|
||||
db := dao.GetDB()
|
||||
snapshotAt := utils.Time2Date(time.Now().AddDate(0, 0, -1))
|
||||
dao.DeletePriceReferHistory(db, utils.Time2Date(snapshotAt.AddDate(0, 0, -7)))
|
||||
priceReferSnapshotDelete := &model.PriceReferSnapshot{SnapshotAt: snapshotAt}
|
||||
dao.DeleteEntity(db, priceReferSnapshotDelete, "SnapshotAt")
|
||||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
priceReferSnapshot, err := dao.GetStatisticsReportForStoreSkusPrice(db, cityCodes, skuIDs)
|
||||
if len(priceReferSnapshot) > 0 {
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
for _, v := range priceReferSnapshot {
|
||||
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
|
||||
v.SnapshotAt = snapshotAt
|
||||
}
|
||||
dao.CreateMultiEntities(db, priceReferSnapshot)
|
||||
dao.Commit(db)
|
||||
}
|
||||
case 1:
|
||||
priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, nil, nil, nil, snapshotAt)
|
||||
var (
|
||||
citySkuMap = make(map[int]map[int][]int)
|
||||
countryMap = make(map[int][]int)
|
||||
resultMap = make(map[int]map[int]*model.PriceReferSnapshot)
|
||||
resultCountryMap = make(map[int]*model.PriceReferSnapshot)
|
||||
)
|
||||
storeList, err := dao.GetStoreList(db, nil, nil, nil, nil, "")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for _, v := range storeList {
|
||||
if v.PayPercentage < 50 {
|
||||
continue
|
||||
}
|
||||
var tList []*tStoreSkuBindAndSkuName
|
||||
sql := `
|
||||
SELECT DISTINCT b.city_code, a.store_id, Round(a.unit_price * IF(b.pay_percentage < 50 , 70, b.pay_percentage) / 100) AS unit_price, c.name_id
|
||||
FROM store_sku_bind a
|
||||
JOIN store b ON b.id = a.store_id AND b.deleted_at = ? AND b.status != ?
|
||||
JOIN sku c ON c.id = a.sku_id
|
||||
WHERE a.store_id = ?
|
||||
AND c.name_id NOT IN(
|
||||
SELECT b.name_id
|
||||
FROM store_sku_bind a
|
||||
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
|
||||
WHERE a.deleted_at = ?
|
||||
AND a.store_id = ?
|
||||
AND b.name_id NOT IN(SELECT DISTINCT b.name_id
|
||||
FROM store_sku_bind a
|
||||
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
|
||||
WHERE a.deleted_at = ?
|
||||
AND a.store_id = ?
|
||||
AND a.status = ?)
|
||||
)
|
||||
AND a.deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
model.StoreStatusDisabled,
|
||||
v.ID,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
v.ID,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
v.ID,
|
||||
model.StoreSkuBindStatusNormal,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
dao.GetRows(db, &tList, sql, sqlParams...)
|
||||
skuNameMap := make(map[int][]int)
|
||||
if len(tList) > 0 {
|
||||
for _, vv := range tList {
|
||||
skuNameMap[vv.NameID] = append(skuNameMap[vv.NameID], vv.UnitPrice)
|
||||
countryMap[vv.NameID] = append(countryMap[vv.NameID], vv.UnitPrice)
|
||||
}
|
||||
if citySkuMap[v.CityCode] != nil {
|
||||
for nameID, unitPriceList := range skuNameMap {
|
||||
if citySkuMap[v.CityCode][nameID] != nil {
|
||||
citySkuMap[v.CityCode][nameID] = append(citySkuMap[v.CityCode][nameID], unitPriceList...)
|
||||
} else {
|
||||
citySkuMap[v.CityCode][nameID] = unitPriceList
|
||||
}
|
||||
}
|
||||
} else {
|
||||
citySkuMap[v.CityCode] = skuNameMap
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range countryMap {
|
||||
var midUnitPrice int
|
||||
var avgUnitPrice int
|
||||
sort.Ints(v)
|
||||
if len(v)%2 == 0 {
|
||||
midUnitPrice = v[len(v)/2-1]
|
||||
} else {
|
||||
midUnitPrice = v[len(v)/2]
|
||||
}
|
||||
for _, vv := range v {
|
||||
avgUnitPrice += vv
|
||||
}
|
||||
priceRefer := &model.PriceReferSnapshot{
|
||||
MidUnitPrice: midUnitPrice,
|
||||
MaxUnitPrice: v[len(v)-1],
|
||||
MinUnitPrice: v[0],
|
||||
AvgUnitPrice: avgUnitPrice / len(v),
|
||||
}
|
||||
resultCountryMap[k] = priceRefer
|
||||
}
|
||||
for k1, v := range citySkuMap {
|
||||
skuNameMap := make(map[int]*model.PriceReferSnapshot)
|
||||
for k2, _ := range v {
|
||||
var midUnitPrice int
|
||||
var avgUnitPrice int
|
||||
sort.Ints(v[k2])
|
||||
if len(v[k2])%2 == 0 {
|
||||
midUnitPrice = v[k2][len(v[k2])/2-1]
|
||||
} else {
|
||||
midUnitPrice = v[k2][len(v[k2])/2]
|
||||
}
|
||||
for _, vv := range v[k2] {
|
||||
avgUnitPrice += vv
|
||||
}
|
||||
skuNameMap[k2] = &model.PriceReferSnapshot{
|
||||
MidUnitPrice: midUnitPrice,
|
||||
MaxUnitPrice: v[k2][len(v[k2])-1],
|
||||
MinUnitPrice: v[k2][0],
|
||||
AvgUnitPrice: avgUnitPrice / len(v[k2]),
|
||||
}
|
||||
}
|
||||
resultMap[k1] = skuNameMap
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if len(priceReferSnapshotList) > 0 {
|
||||
for _, v := range priceReferSnapshotList {
|
||||
if v.CityCode == 0 {
|
||||
if resultCountryMap[v.NameID] != nil {
|
||||
v.MidUnitPrice = resultCountryMap[v.NameID].MidUnitPrice
|
||||
v.MaxUnitPrice = resultCountryMap[v.NameID].MaxUnitPrice
|
||||
v.AvgUnitPrice = resultCountryMap[v.NameID].AvgUnitPrice
|
||||
v.MinUnitPrice = resultCountryMap[v.NameID].MinUnitPrice
|
||||
dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if resultMap[v.CityCode][v.NameID] != nil {
|
||||
v.MidUnitPrice = resultMap[v.CityCode][v.NameID].MidUnitPrice
|
||||
v.MaxUnitPrice = resultMap[v.CityCode][v.NameID].MaxUnitPrice
|
||||
v.AvgUnitPrice = resultMap[v.CityCode][v.NameID].AvgUnitPrice
|
||||
v.MinUnitPrice = resultMap[v.CityCode][v.NameID].MinUnitPrice
|
||||
dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
case 2:
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if len(priceReferSnapshotList) > 0 {
|
||||
for _, v := range priceReferSnapshotList {
|
||||
result, _ := dao.GetPriceReferPrice(db, v.CityCode, v.SkuID, snapshotAt)
|
||||
v.MaxPrice = result.MaxPrice
|
||||
v.MinPrice = result.MinPrice
|
||||
v.AvgPrice = result.AvgPrice
|
||||
v.MidPrice = result.MidPrice
|
||||
dao.UpdateEntity(db, v, "MidPrice", "MaxPrice", "MinPrice", "AvgPrice")
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
//TODO 京东查询接口报错,暂时屏蔽了
|
||||
// case 3:
|
||||
// priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, []int{0}, nil, nil, snapshotAt)
|
||||
// taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// v := batchItemList[0].(*model.PriceReferSnapshot)
|
||||
// for _, appOrg := range apimanager.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD) {
|
||||
// directPrice, _ := jd.GetAPI(appOrg).GetJdSkuDirectPrice(v.SkuID)
|
||||
// v.JdDirectPrice = int(directPrice)
|
||||
// dao.UpdateEntity(db, v, "JdDirectPrice")
|
||||
// }
|
||||
// return retVal, err
|
||||
// }
|
||||
// taskParallel := tasksch.NewParallelTask("获取并更新京东指导价格", tasksch.NewParallelConfig(), ctx, taskFunc, priceReferSnapshotList)
|
||||
// tasksch.HandleTask(taskParallel, task, true).Run()
|
||||
// _, err = taskParallel.GetResult(0)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
taskSeq := tasksch.NewSeqTask2("生成每日价格统计", ctx, isContinueWhenError, taskSeqFunc, 3)
|
||||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||||
if !isAsync {
|
||||
_, err = taskSeq.GetResult(0)
|
||||
hint = "1"
|
||||
} else {
|
||||
hint = taskSeq.GetID()
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
package tempop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestJdStoreInfo1125(t *testing.T) {
|
||||
_, err := JdStoreInfo1125()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Testaa(t *testing.T) {
|
||||
request, _ := http.NewRequest(http.MethodGet, "https://stores.shop.jd.com/stores/updateStoreStatus?storeId=24332466&storeStatus=1", nil)
|
||||
c := &http.Cookie{
|
||||
Name: "thor",
|
||||
Value: "80FAF09E9A09B6E618A68057BDFCFCB8C86E8252DC9F7D3B34572625904FBA0AB6BF053A5325612EC0407791BB05F5301356E71E8B282C40C06D0B5DF3439DEECB102A78FAFF7AC0FC4E2D1FA8DD8BBAE1A011E50B5C74F1870AD982D7BF453F470F31F2241B73AC4C25485025C2ABEBC8A538AF7257824D2FAEE300A1435175B0B451FB5C19B78D729FC83152CA3BAF",
|
||||
}
|
||||
request.AddCookie(c)
|
||||
client := &http.Client{}
|
||||
fmt.Println("test1", request.URL)
|
||||
response, _ := client.Do(request)
|
||||
defer response.Body.Close()
|
||||
bodyData, _ := ioutil.ReadAll(response.Body)
|
||||
fmt.Println("test1", string(bodyData))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,15 +9,12 @@ import (
|
||||
"image/png"
|
||||
"net/http"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/qiniu/api.v7/storage"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -51,23 +48,24 @@ func Binary2Image(binaryData []byte, mimeType string) (img image.Image, outMimeT
|
||||
}
|
||||
|
||||
func GetQiniuUploadToken(ctx *jxcontext.Context, suffix, hashCode string) (upTokenInfo *UploadResTokenInfo, err error) {
|
||||
imgURL := ""
|
||||
if hashCode != "" {
|
||||
imgURL, _ = GetDataResource(ctx, hashCode)
|
||||
}
|
||||
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: globals.QiniuBucket,
|
||||
Expires: qiniuTokenExpires,
|
||||
}
|
||||
upTokenInfo = &UploadResTokenInfo{
|
||||
Token: putPolicy.UploadToken(api.QiniuAPI),
|
||||
Expires: putPolicy.Expires,
|
||||
FileName: jxutils.GenPicFileName(suffix),
|
||||
Hit: imgURL != "",
|
||||
Img: imgURL,
|
||||
}
|
||||
return upTokenInfo, err
|
||||
//imgURL := ""
|
||||
//if hashCode != "" {
|
||||
// imgURL, _ = GetDataResource(ctx, hashCode)
|
||||
//}
|
||||
//
|
||||
//putPolicy := storage.PutPolicy{
|
||||
// Scope: globals.QiniuBucket,
|
||||
// Expires: qiniuTokenExpires,
|
||||
//}
|
||||
//upTokenInfo = &UploadResTokenInfo{
|
||||
// Token: putPolicy.UploadToken(api.QiniuAPI),
|
||||
// Expires: putPolicy.Expires,
|
||||
// FileName: jxutils.GenPicFileName(suffix),
|
||||
// Hit: imgURL != "",
|
||||
// Img: imgURL,
|
||||
//}
|
||||
//return upTokenInfo, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 此函数要求resBinary不能空,mimeType与hashCode必须是正确的
|
||||
@@ -109,10 +107,10 @@ func RegisterDataResource(ctx *jxcontext.Context, name, resourceURL, mimeType, h
|
||||
return dataRes, err
|
||||
}
|
||||
if imgType > 0 {
|
||||
if globals.EnableStoreWrite {
|
||||
//if globals.EnableStoreWrite {
|
||||
// 忽略上传错误
|
||||
UploadImage2Vendors(ctx, nil, dataRes, resBinary, isAsyncUpload2Vendor)
|
||||
}
|
||||
//}
|
||||
}
|
||||
return dataRes, err
|
||||
}
|
||||
@@ -152,82 +150,82 @@ func GetDataResource(ctx *jxcontext.Context, hashCode string) (resourceURL strin
|
||||
|
||||
// 这个函数,可能部分平台成功,部分失败
|
||||
func UploadImage2Vendors(ctx *jxcontext.Context, parentTask tasksch.ITask, dataRes *model.DataResource, imgData []byte, isAsync bool) (hint string, err error) {
|
||||
var vendorIDs []int
|
||||
if dataRes.EbaiURL == "" {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDEBAI)
|
||||
}
|
||||
if dataRes.MtwmURL == "" {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDMTWM)
|
||||
}
|
||||
// var vendorIDs []int
|
||||
// if dataRes.EbaiURL == "" {
|
||||
// vendorIDs = append(vendorIDs, model.VendorIDEBAI)
|
||||
// }
|
||||
// if dataRes.MtwmURL == "" {
|
||||
// vendorIDs = append(vendorIDs, model.VendorIDMTWM)
|
||||
// }
|
||||
// if dataRes.JdsURL == "" {
|
||||
// vendorIDs = append(vendorIDs, model.VendorIDJDShop)
|
||||
// }
|
||||
if len(vendorIDs) > 0 {
|
||||
imgName := jxutils.GetShortNameFromURL(dataRes.MainURL)
|
||||
task := tasksch.NewSeqTask(fmt.Sprintf("上传图片至平台1:%s,%s", dataRes.Name, dataRes.MainURL), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
if imgData == nil {
|
||||
if imgData, _, err = jxutils.DownloadFileByURL(dataRes.MainURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
uploadTask := tasksch.NewParallelTask(fmt.Sprintf("上传图片至平台2:%s,%s", dataRes.Name, imgName),
|
||||
tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorID := batchItemList[0].(int)
|
||||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||||
// TODO vendorOrgCode
|
||||
imgHint, err2 := handler.UploadImg(ctx, "", dataRes.MainURL, imgData, imgName, int(dataRes.UseType))
|
||||
if err = err2; err == nil {
|
||||
retVal = [][]interface{}{
|
||||
[]interface{}{
|
||||
vendorID,
|
||||
imgHint,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, vendorIDs)
|
||||
tasksch.HandleTask(uploadTask, task, false).Run()
|
||||
resultList, err2 := uploadTask.GetResult(0)
|
||||
err = err2
|
||||
if len(resultList) > 0 {
|
||||
db := dao.GetDB()
|
||||
for _, v := range resultList {
|
||||
result := v.([]interface{})
|
||||
vendorID := result[0].(int)
|
||||
imgHint := result[1].(string)
|
||||
updateField := ""
|
||||
if vendorID == model.VendorIDEBAI {
|
||||
dataRes.EbaiURL = imgHint
|
||||
updateField = "EbaiURL"
|
||||
} else if vendorID == model.VendorIDMTWM {
|
||||
dataRes.MtwmURL = imgHint
|
||||
updateField = "MtwmURL"
|
||||
}
|
||||
// else if vendorID == model.VendorIDJDShop {
|
||||
// dataRes.JdsURL = imgHint
|
||||
// updateField = "JdsURL"
|
||||
// if len(vendorIDs) > 0 {
|
||||
// imgName := jxutils.GetShortNameFromURL(dataRes.MainURL)
|
||||
// task := tasksch.NewSeqTask(fmt.Sprintf("上传图片至平台1:%s,%s", dataRes.Name, dataRes.MainURL), ctx,
|
||||
// func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
// switch step {
|
||||
// case 0:
|
||||
// if imgData == nil {
|
||||
// if imgData, _, err = jxutils.DownloadFileByURL(dataRes.MainURL); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// }
|
||||
// case 1:
|
||||
// uploadTask := tasksch.NewParallelTask(fmt.Sprintf("上传图片至平台2:%s,%s", dataRes.Name, imgName),
|
||||
// tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// vendorID := batchItemList[0].(int)
|
||||
// if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||||
// // TODO vendorOrgCode
|
||||
// imgHint, err2 := handler.UploadImg(ctx, "", dataRes.MainURL, imgData, imgName, int(dataRes.UseType))
|
||||
// if err = err2; err == nil {
|
||||
// retVal = [][]interface{}{
|
||||
// []interface{}{
|
||||
// vendorID,
|
||||
// imgHint,
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return retVal, err
|
||||
// }, vendorIDs)
|
||||
// tasksch.HandleTask(uploadTask, task, false).Run()
|
||||
// resultList, err2 := uploadTask.GetResult(0)
|
||||
// err = err2
|
||||
// if len(resultList) > 0 {
|
||||
// db := dao.GetDB()
|
||||
// for _, v := range resultList {
|
||||
// result := v.([]interface{})
|
||||
// vendorID := result[0].(int)
|
||||
// imgHint := result[1].(string)
|
||||
// updateField := ""
|
||||
// if vendorID == model.VendorIDEBAI {
|
||||
// dataRes.EbaiURL = imgHint
|
||||
// updateField = "EbaiURL"
|
||||
// } else if vendorID == model.VendorIDMTWM {
|
||||
// dataRes.MtwmURL = imgHint
|
||||
// updateField = "MtwmURL"
|
||||
// }
|
||||
// // else if vendorID == model.VendorIDJDShop {
|
||||
// // dataRes.JdsURL = imgHint
|
||||
// // updateField = "JdsURL"
|
||||
// // }
|
||||
// dao.UpdateEntity(db, dataRes, updateField)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return result, err
|
||||
// }, 2)
|
||||
// tasksch.HandleTask(task, parentTask, false).Run()
|
||||
// if !isAsync {
|
||||
// if _, err = task.GetResult(0); err == nil {
|
||||
// hint = "1"
|
||||
// }
|
||||
// } else {
|
||||
// hint = task.GetID()
|
||||
// }
|
||||
// }
|
||||
dao.UpdateEntity(db, dataRes, updateField)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}, 2)
|
||||
tasksch.HandleTask(task, parentTask, false).Run()
|
||||
if !isAsync {
|
||||
if _, err = task.GetResult(0); err == nil {
|
||||
hint = "1"
|
||||
}
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
|
||||
@@ -7,17 +7,11 @@ import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestGetQiniuUploadToken(t *testing.T) {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
package ddmsg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/dingding"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func SendDDUserMessage(msgType, ddUserID, title, content string) (err error) {
|
||||
globals.SugarLogger.Debugf("SendDDUserMessage ddUserID:%s, title:%s", ddUserID, title)
|
||||
if globals.IsProductEnv() {
|
||||
if msgType == dingdingapi.MsgTyeText {
|
||||
err = api.DingDingAPI.CorpAsyncSendSimple(ddUserID, content)
|
||||
} else if msgType == dingdingapi.MsgTypeMarkdown {
|
||||
err = api.DingDingAPI.CorpAsyncSendMarkdown([]string{ddUserID}, nil, false, title, content)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SendUserMessage(msgType, userID, title, content string) (err error) {
|
||||
globals.SugarLogger.Debugf("SendUserMessage userID:%s, title:%s", userID, title)
|
||||
authList, err := auth2.GetUserBindAuthInfo(userID)
|
||||
findOneMethod := false
|
||||
if err == nil {
|
||||
for _, auth := range authList {
|
||||
if auth.Type == dingding.AuthTypeStaff /*|| auth.Type == weixin.AuthTypeMP*/ {
|
||||
findOneMethod = true
|
||||
if len(content) > dingdingapi.MaxWorkContentLen {
|
||||
content = content[:dingdingapi.MaxWorkContentLen-4] + "..."
|
||||
}
|
||||
err = SendDDUserMessage(msgType, auth.AuthID, title, content)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !findOneMethod {
|
||||
err = fmt.Errorf("用户[%s]找不到至少一个有效的通讯方式", userID)
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("SendUserMessage userID:%s, title:%s, content:%s failed with error:%v", userID, title, content, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SendUsersMessage(msgType string, userIDs []string, title, content string) (err error) {
|
||||
errList := errlist.New()
|
||||
for _, userID := range userIDs {
|
||||
errList.AddErr(SendUserMessage(msgType, userID, title, content))
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/refutil"
|
||||
)
|
||||
|
||||
@@ -101,15 +101,12 @@ func (h *Hub) GetToken(tokenType, oldToken string, waitTime time.Duration) (toke
|
||||
case EventTypeWXToken:
|
||||
token = api.WeixinAPI.CBGetToken()
|
||||
case EventTypeYLYToken:
|
||||
token = api.YilianyunAPI.GetToken()
|
||||
case EventTypeWeimobToken:
|
||||
if weimobToken := api.WeimobAPI.GetToken(); weimobToken != nil {
|
||||
token = string(utils.MustMarshal(weimobToken))
|
||||
}
|
||||
case EventTypePushToken:
|
||||
token = api.PushAPI.CBGetToken()
|
||||
case EventTypeWX2Token:
|
||||
token = api.WeixinMiniAPI2.CBGetToken()
|
||||
}
|
||||
|
||||
if token != oldToken {
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
@@ -25,6 +24,8 @@ type Context struct {
|
||||
|
||||
const (
|
||||
MaxUserNameLen = 30
|
||||
|
||||
RsmDefultToken = "rushSkyMonkeyToken_20201203"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -72,7 +73,10 @@ func New(notUsed interface{}, token string, w http.ResponseWriter, r *http.Reque
|
||||
// }
|
||||
}
|
||||
if err == model.ErrTokenIsInvalid {
|
||||
if !globals.IsProductEnv() {
|
||||
//if !globals.IsProductEnv() {
|
||||
// err = nil
|
||||
//} else
|
||||
if token == RsmDefultToken {
|
||||
err = nil
|
||||
} else {
|
||||
errCode = model.ErrCodeTokenIsInvalid
|
||||
@@ -158,14 +162,3 @@ func (ctx *Context) GetUserID() (userID string) {
|
||||
}
|
||||
return userID
|
||||
}
|
||||
|
||||
func (ctx *Context) GetFullUser() (user *model.User) {
|
||||
token := ctx.GetToken()
|
||||
authInfo, err2 := auth2.GetTokenInfo(token)
|
||||
if err2 == nil {
|
||||
if authInfo.TokenType == auth2.TokenTypeNormal {
|
||||
user, _ = dao.GetUserByID(dao.GetDB(), "user_id", authInfo.GetID())
|
||||
}
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package jxutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
@@ -11,19 +9,12 @@ import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/routinepool"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/qiniu/api.v7/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -42,33 +33,19 @@ var (
|
||||
model.VendorIDEBAI: []string{
|
||||
"image-star.elemecdn.com",
|
||||
},
|
||||
model.VendorIDYB: []string{
|
||||
"pospalstoreimg.area27.pospal.cn",
|
||||
},
|
||||
}
|
||||
|
||||
letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
flowUnitMap = map[string]string{
|
||||
"KB": "KB",
|
||||
"MB": "MB",
|
||||
"GB": "GB",
|
||||
}
|
||||
)
|
||||
|
||||
const fileExt = ".xlsx"
|
||||
|
||||
type OrderSkuList []*model.OrderSku
|
||||
|
||||
func (l OrderSkuList) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
// Less reports whether the element with
|
||||
// index i should sort before the element with index j.
|
||||
func (l OrderSkuList) Less(i, j int) bool {
|
||||
return l[i].SalePrice < l[j].SalePrice
|
||||
}
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
func (l OrderSkuList) Swap(i, j int) {
|
||||
tmp := l[i]
|
||||
l[i] = l[j]
|
||||
l[j] = tmp
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
routinePool = routinepool.New(1000, 1000)
|
||||
@@ -80,99 +57,20 @@ func init() {
|
||||
orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix()
|
||||
}
|
||||
|
||||
func getJxStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
|
||||
if order.JxStoreID != 0 {
|
||||
return order.JxStoreID
|
||||
func RandStringBytes(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
||||
}
|
||||
return order.StoreID
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// 此函数得到的是order的销售门店京西ID,与GetJxStoreIDFromOrder的区别是order.StoreID的解释不同,参考其它相关资料
|
||||
func GetSaleStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
|
||||
return getJxStoreIDFromOrder(order)
|
||||
}
|
||||
|
||||
// 此函数得到的是order的商品的展示门店京西ID,与GetJxStoreIDFromOrder的区别是order.StoreID的解释不同,参考其它相关资料
|
||||
func GetShowStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
|
||||
return getJxStoreIDFromOrder(order)
|
||||
}
|
||||
|
||||
func GetSkuIDFromOrderSku(sku *model.OrderSku) (skuID int) {
|
||||
if sku.JxSkuID > 0 {
|
||||
return sku.JxSkuID
|
||||
}
|
||||
return sku.SkuID
|
||||
}
|
||||
|
||||
func GetSaleStoreIDFromAfsOrder(order *model.AfsOrder) (retVal int) {
|
||||
if order.JxStoreID > 0 {
|
||||
return order.JxStoreID
|
||||
}
|
||||
return order.StoreID
|
||||
}
|
||||
|
||||
func GetSkuIDFromOrderSkuFinancial(sku *model.OrderSkuFinancial) (skuID int) {
|
||||
if sku.JxSkuID > 0 {
|
||||
return sku.JxSkuID
|
||||
}
|
||||
return sku.SkuID
|
||||
}
|
||||
|
||||
func SplitUniversalOrderID(universalOrderID string) (orderID string, vendorID int) {
|
||||
index := strings.Index(universalOrderID, "|")
|
||||
if index != -1 {
|
||||
orderID = universalOrderID[:index]
|
||||
vendorID = int(utils.Str2Int64(universalOrderID[index+1:]))
|
||||
} else {
|
||||
if vendorID = GetPossibleVendorIDFromVendorOrderID(universalOrderID); vendorID == model.VendorIDUnknown {
|
||||
// globals.SugarLogger.Errorf("unkown order type:%v", universalOrderID)
|
||||
panic(fmt.Sprintf("unkown order type, orderID:%s", universalOrderID))
|
||||
}
|
||||
orderID = universalOrderID
|
||||
}
|
||||
return orderID, vendorID
|
||||
}
|
||||
|
||||
func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
|
||||
vendorID = model.VendorIDUnknown
|
||||
if vendorOrderIDInt64 := utils.Str2Int64WithDefault(vendorOrderID, 0); vendorOrderIDInt64 > 0 {
|
||||
orderIDLen := len(vendorOrderID)
|
||||
// 5287873015048 13 wsc
|
||||
// 15380342248732 14 old ebai order
|
||||
// 800402581000221 15,16 jd order
|
||||
// 33437032333978492 17 mtwm order
|
||||
// 3022716176275221584 19 elm order, new ebai order
|
||||
|
||||
// 京东到家从2020年开始订单号的长度都会在现有基础上加一位,订单号的前两位取的是当年的最后两位数(如:2020取的20),以适应业务的发展。
|
||||
// 改造点:
|
||||
// 1、订单号位数变化,由原有15位数增加1位数调整为16位数,对接商家需检查是否有对订单号位数做长度校验。
|
||||
// 2、第一位数字发生变化,由原来9开头调整为当年年份后两位数如:2020年订单开头为20;
|
||||
if orderIDLen == len("925265130002541") || orderIDLen == len("1925265130002541") {
|
||||
vendorID = model.VendorIDJD
|
||||
} else if orderIDLen == len("3022716176275221584") {
|
||||
// vendorID = model.VendorIDELM
|
||||
vendorID = model.VendorIDEBAI // 饿百零售开放平台订单接口中订单ID“order_id”字段长度将调整为19位,和饿了么订单ID“eleme_order_id”字段格式保持一致。
|
||||
} else if orderIDLen == len("15380342248732") {
|
||||
if vendorOrderID[:2] == "88" {
|
||||
vendorID = model.VendorIDJX
|
||||
} else {
|
||||
vendorID = model.VendorIDEBAI
|
||||
}
|
||||
} else if orderIDLen == len("33437032333978492") {
|
||||
vendorID = model.VendorIDMTWM
|
||||
} else if orderIDLen == len("5287873015048") {
|
||||
vendorID = model.VendorIDWSC
|
||||
} else if orderIDLen == len("1000004390") {
|
||||
vendorID = model.VendorIDJX
|
||||
} else if orderIDLen == len("124557362562000001") || orderIDLen == len("13153183146800000100") {
|
||||
vendorID = model.VendorIDJDShop
|
||||
}
|
||||
}
|
||||
return vendorID
|
||||
func GenRand6() (num int) {
|
||||
return utils.Str2Int(fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000)))
|
||||
}
|
||||
|
||||
func GenOrderNo() (orderNo int64) {
|
||||
const prefix = 88
|
||||
var prefix = utils.Str2Int64(time.Now().Format("20060102"))
|
||||
const randPartNum = 1000
|
||||
orderNo = time.Now().Unix() - orderNoBeginTimestamp
|
||||
orderNo = orderNo * randPartNum
|
||||
@@ -186,53 +84,6 @@ func GenOrderNo() (orderNo int64) {
|
||||
return orderNo
|
||||
}
|
||||
|
||||
func GenAfsOrderNo() (orderNo int64) {
|
||||
const prefix = 80
|
||||
const randPartNum = 100
|
||||
orderNo = time.Now().Unix() - orderNoBeginTimestamp
|
||||
orderNo = orderNo * randPartNum
|
||||
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
|
||||
randPart := 0
|
||||
for k, v := range md5Bytes {
|
||||
randPart += int(v) << ((k % 3) * 8)
|
||||
}
|
||||
orderNo += int64(randPart % randPartNum)
|
||||
orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix
|
||||
return orderNo
|
||||
}
|
||||
|
||||
func GetPossibleVendorIDFromAfsOrderID(afsOrderID string) (vendorID int) {
|
||||
vendorID = model.VendorIDUnknown
|
||||
if afsOrderIDInt64 := utils.Str2Int64WithDefault(afsOrderID, 0); afsOrderIDInt64 > 0 {
|
||||
orderIDLen := len(afsOrderID)
|
||||
if orderIDLen == len("22586438") { // 8
|
||||
vendorID = model.VendorIDJD
|
||||
} else if orderIDLen == len("1413138834") { // 10
|
||||
vendorID = model.VendorIDEBAI
|
||||
} else if orderIDLen == len("29488498752") { // 11
|
||||
vendorID = model.VendorIDMTWM
|
||||
}
|
||||
}
|
||||
return vendorID
|
||||
}
|
||||
|
||||
func ComposeUniversalOrderID(orderID string, vendorID int) string {
|
||||
// return fmt.Sprintf("%s|%d", orderID, vendorID)
|
||||
return orderID // 当前用长度就能区分,先不加上vendorID
|
||||
}
|
||||
|
||||
func GetUniversalOrderIDFromWaybill(bill *model.Waybill) string {
|
||||
return ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID)
|
||||
}
|
||||
|
||||
func GetUniversalOrderIDFromOrder(order *model.GoodsOrder) string {
|
||||
return ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)
|
||||
}
|
||||
|
||||
func GetUniversalOrderIDFromOrderStatus(status *model.OrderStatus) string {
|
||||
return ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)
|
||||
}
|
||||
|
||||
// distance单位为米
|
||||
func ConvertDistanceToLogLat(lng, lat, distance, angle float64) (newLng, newLat float64) {
|
||||
oneDu := 111319.55 // 单位为米
|
||||
@@ -257,16 +108,6 @@ func EarthDistance(lng1, lat1, lng2, lat2 float64) float64 {
|
||||
return dist * radius
|
||||
}
|
||||
|
||||
// 返回结果单元为公里
|
||||
func WalkingDistance(lng1, lat1, lng2, lat2 float64) (distance float64) {
|
||||
if distance = api.AutonaviAPI.WalkingDistance(lng1, lat1, lng2, lat2); distance == 0 {
|
||||
distance = EarthDistance(lng1, lat1, lng2, lat2) * 1.4
|
||||
} else {
|
||||
distance /= 1000
|
||||
}
|
||||
return distance
|
||||
}
|
||||
|
||||
func StandardCoordinate2Int(value float64) int {
|
||||
return int(math.Round(value * 1000000))
|
||||
}
|
||||
@@ -275,25 +116,6 @@ func IntCoordinate2Standard(value int) float64 {
|
||||
return float64(value) / 1000000
|
||||
}
|
||||
|
||||
func IntCoordinate2MarsStandard(gpsLng, gpsLat int, coordinateType int) (marsLng, marsLat float64, err error) {
|
||||
marsLng = IntCoordinate2Standard(gpsLng)
|
||||
marsLat = IntCoordinate2Standard(gpsLat)
|
||||
coordSys := ""
|
||||
switch coordinateType {
|
||||
case model.CoordinateTypeGPS:
|
||||
coordSys = autonavi.CoordSysGPS
|
||||
case model.CoordinateTypeMars:
|
||||
return marsLng, marsLat, nil
|
||||
case model.CoordinateTypeBaiDu:
|
||||
coordSys = autonavi.CoordSysBaidu
|
||||
case model.CoordinateTypeMapbar:
|
||||
coordSys = autonavi.CoordSysMapbar
|
||||
default:
|
||||
panic(fmt.Sprintf("known coordinate type:%d", coordinateType))
|
||||
}
|
||||
return api.AutonaviAPI.CoordinateConvert(marsLng, marsLat, coordSys)
|
||||
}
|
||||
|
||||
func IntPrice2Standard(value int64) float64 {
|
||||
return float64(value) / 100
|
||||
}
|
||||
@@ -555,7 +377,7 @@ func MakeValidationMapFromSlice(validValues []string, flag int) map[string]int {
|
||||
}
|
||||
|
||||
func ComposeQiniuResURL(key string) string {
|
||||
return "http://image.jxc4.com/" + key
|
||||
return "https://image.jxc4.com/" + key
|
||||
}
|
||||
|
||||
func IsLegalMobileNumber(num int64) bool {
|
||||
@@ -595,151 +417,6 @@ func Strings2Objs(strAndObjAddPairs ...interface{}) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func RefreshOrderSkuRelated(order *model.GoodsOrder) *model.GoodsOrder {
|
||||
order.SkuCount = 0
|
||||
order.GoodsCount = 0
|
||||
order.SalePrice = 0
|
||||
order.VendorPrice = 0
|
||||
order.ShopPrice = 0
|
||||
order.Weight = 0
|
||||
order.EarningPrice = 0
|
||||
for _, sku := range order.Skus {
|
||||
if sku.SkuID > math.MaxInt32 {
|
||||
sku.SkuID = sku.JxSkuID
|
||||
}
|
||||
sku.OrderCreatedAt = order.OrderCreatedAt
|
||||
sku.VendorID = order.VendorID
|
||||
sku.VendorOrderID = order.VendorOrderID
|
||||
order.SkuCount++
|
||||
order.GoodsCount += sku.Count
|
||||
order.SalePrice += sku.SalePrice * int64(sku.Count)
|
||||
order.VendorPrice += sku.VendorPrice * int64(sku.Count)
|
||||
order.ShopPrice += sku.ShopPrice * int64(sku.Count)
|
||||
order.EarningPrice += sku.EarningPrice * int64(sku.Count)
|
||||
order.Weight += sku.Weight * sku.Count
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func RefreshOrderEarningPrice2(order *model.GoodsOrder, payPercentage int) *model.GoodsOrder {
|
||||
if order.EarningType == model.EarningTypePoints {
|
||||
// if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
|
||||
// order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage)) / 100
|
||||
// } else {
|
||||
order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage/2)) / 100
|
||||
// }
|
||||
} else {
|
||||
order.NewEarningPrice = order.EarningPrice
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func RefreshOrderEarningPrice3(order *model.GoodsOrder, payPercentage int, bill *model.Waybill) *model.GoodsOrder {
|
||||
if order.EarningType == model.EarningTypePoints {
|
||||
// if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
|
||||
// order.NewEarningPrice = (order.TotalShopMoney - bill.DesiredFee) * int64((100 - payPercentage)) / 100
|
||||
// } else {
|
||||
order.NewEarningPrice = order.TotalShopMoney*int64((100-payPercentage/2))/100 - bill.DesiredFee
|
||||
// }
|
||||
} else {
|
||||
order.NewEarningPrice = order.EarningPrice
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func RefreshAfsOrderSkuRelated(afsOrder *model.AfsOrder) *model.AfsOrder {
|
||||
afsOrder.SkuUserMoney = 0
|
||||
afsOrder.PmSkuSubsidyMoney = 0
|
||||
for _, orderSku := range afsOrder.Skus {
|
||||
if orderSku.SkuID > math.MaxInt32 {
|
||||
orderSku.SkuID = orderSku.JxSkuID
|
||||
}
|
||||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||||
afsOrder.PmSkuSubsidyMoney += orderSku.PmSkuSubsidyMoney
|
||||
}
|
||||
return afsOrder
|
||||
}
|
||||
|
||||
func RemoveSkuFromOrder(order *model.GoodsOrder, removedSkuList []*model.OrderSku) *model.GoodsOrder {
|
||||
removedSkuMap := make(map[int]*model.OrderSku)
|
||||
removedSkuMap2 := make(map[string]*model.OrderSku)
|
||||
for _, sku := range removedSkuList {
|
||||
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
|
||||
if removedSkuMap[skuID] == nil {
|
||||
removedSkuMap[skuID] = sku
|
||||
} else {
|
||||
removedSkuMap[skuID].Count += sku.Count
|
||||
}
|
||||
}
|
||||
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
|
||||
if removedSkuMap2[vendorSkuID] == nil {
|
||||
removedSkuMap2[vendorSkuID] = sku
|
||||
} else {
|
||||
removedSkuMap2[vendorSkuID].Count += sku.Count
|
||||
}
|
||||
}
|
||||
}
|
||||
var skuList []*model.OrderSku
|
||||
sort.Sort(sort.Reverse(OrderSkuList(order.Skus)))
|
||||
for _, sku := range order.Skus {
|
||||
var removedSku *model.OrderSku
|
||||
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
|
||||
removedSku = removedSkuMap[skuID]
|
||||
}
|
||||
if removedSku == nil {
|
||||
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
|
||||
removedSku = removedSkuMap2[vendorSkuID]
|
||||
}
|
||||
}
|
||||
copiedSku := *sku
|
||||
tmp := &copiedSku
|
||||
if removedSku != nil {
|
||||
if removedSku.Count >= sku.Count {
|
||||
tmp = nil
|
||||
removedSku.Count -= sku.Count
|
||||
} else {
|
||||
tmp.Count -= removedSku.Count
|
||||
removedSku.Count = 0
|
||||
}
|
||||
}
|
||||
if tmp != nil {
|
||||
skuList = append(skuList, tmp)
|
||||
}
|
||||
}
|
||||
order.Skus = skuList
|
||||
return RefreshOrderSkuRelated(order)
|
||||
}
|
||||
|
||||
func UploadExportContent(content []byte, key string) (downloadURL string, err error) {
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: globals.QiniuBucket,
|
||||
Expires: 10 * 60,
|
||||
DeleteAfterDays: 1,
|
||||
}
|
||||
upToken := putPolicy.UploadToken(api.QiniuAPI)
|
||||
cfg := &storage.Config{}
|
||||
formUploader := storage.NewFormUploader(cfg)
|
||||
ret := storage.PutRet{}
|
||||
for i := 0; i < 3; i++ {
|
||||
if err = formUploader.Put(context.Background(), &ret, upToken, key, bytes.NewReader(content), int64(len(content)), &storage.PutExtra{}); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
downloadURL = ComposeQiniuResURL(key)
|
||||
}
|
||||
return downloadURL, err
|
||||
}
|
||||
|
||||
func UploadExeclAndPushMsg(sheetList []*excel.Obj2ExcelSheetConfig, name string) (downloadURL, fileName string, err error) {
|
||||
excelBin := excel.Obj2Excel(sheetList)
|
||||
timeStr := utils.Int64ToStr(time.Now().Unix())
|
||||
fileName = name + timeStr + fileExt
|
||||
baseapi.SugarLogger.Debugf("WriteToExcel:save %s success", fileName)
|
||||
downloadURL, err = UploadExportContent(excelBin, fileName)
|
||||
return downloadURL, fileName, err
|
||||
}
|
||||
|
||||
func TaskResult2Hint(resultList []interface{}) (hint string) {
|
||||
strList := make([]string, len(resultList))
|
||||
for k, v := range resultList {
|
||||
@@ -797,42 +474,15 @@ func OperationTime2Str2(openTime, closeTime int16) (str string) {
|
||||
return str
|
||||
}
|
||||
|
||||
func OperationTimeStr4VendorStore(v *model.VendorStoreSnapshot) (str string) {
|
||||
str = fmt.Sprintf("%s", OperationTime2Str2(v.OpenTime1, v.CloseTime1))
|
||||
if v.OpenTime2 > 0 && v.CloseTime2 > 0 {
|
||||
str += fmt.Sprintf(",%s", OperationTime2Str2(v.OpenTime2, v.CloseTime2))
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func OperationTime2HourMinuteFormat(time time.Time) (i int16) {
|
||||
return int16(time.Hour()*100 + time.Minute())
|
||||
}
|
||||
|
||||
// 得到饿百订单的取货码
|
||||
func GetEbaiOrderGetCode(order *model.GoodsOrder) (getCode string) {
|
||||
if order.VendorID == model.VendorIDEBAI && len(order.VendorOrderID2) >= 4 {
|
||||
getCode = order.VendorOrderID2[len(order.VendorOrderID2)-4:]
|
||||
}
|
||||
return getCode
|
||||
}
|
||||
|
||||
func WriteFile(fileName string, binData []byte) error {
|
||||
err := ioutil.WriteFile(fileName, binData, 0666)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetRealMobile4Order(order *model.GoodsOrder) (mobileNumber string) {
|
||||
mobileNumber = order.ConsigneeMobile2
|
||||
if mobileNumber == "" {
|
||||
mobileNumber = order.ConsigneeMobile
|
||||
}
|
||||
if !IsStringLikeMobile(mobileNumber) {
|
||||
mobileNumber = ""
|
||||
}
|
||||
return mobileNumber
|
||||
}
|
||||
|
||||
func GuessDataResourceVendor(resourceURL string) (vendorID int) {
|
||||
vendorID = -1
|
||||
for tmpVendorID, urlList := range resourceTypeMap {
|
||||
@@ -895,30 +545,23 @@ func GetOneEmailFromStr(str string) (email string) {
|
||||
|
||||
// 计算一个坐标点距离一个门店的距离,单位为米,如果不在有效范围内,则返回0
|
||||
func Point2StoreDistance(lng, lat float64, intStoreLng, intStoreLat int, deliveryRangeType int8, deliveryRange string) (distance int) {
|
||||
storeLng := IntCoordinate2Standard(intStoreLng)
|
||||
storeLat := IntCoordinate2Standard(intStoreLat)
|
||||
if deliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
maxDistance := int(utils.Str2Int64WithDefault(deliveryRange, 0))
|
||||
distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
|
||||
if distance > maxDistance {
|
||||
distance = 0
|
||||
}
|
||||
} else {
|
||||
points := CoordinateStr2Points(deliveryRange)
|
||||
if utils.IsPointInPolygon(lng, lat, points) {
|
||||
distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
|
||||
}
|
||||
}
|
||||
// storeLng := IntCoordinate2Standard(intStoreLng)
|
||||
// storeLat := IntCoordinate2Standard(intStoreLat)
|
||||
// if deliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
// maxDistance := int(utils.Str2Int64WithDefault(deliveryRange, 0))
|
||||
// distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
|
||||
// if distance > maxDistance {
|
||||
// distance = 0
|
||||
// }
|
||||
// } else {
|
||||
// points := CoordinateStr2Points(deliveryRange)
|
||||
// if utils.IsPointInPolygon(lng, lat, points) {
|
||||
// distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
|
||||
// }
|
||||
// }
|
||||
return distance
|
||||
}
|
||||
|
||||
func TranslateStorePriceType(storePriceType int8) int8 {
|
||||
if storePriceType == model.StoreChangePriceTypeManagedStore {
|
||||
storePriceType = model.StoreChangePriceTypeBossDisabled
|
||||
}
|
||||
return storePriceType
|
||||
}
|
||||
|
||||
func TranslateSoundSize(vendorID, soundPercentage int) (soundSize string) {
|
||||
if vendorID == model.VendorIDYiLianYun || vendorID == model.VendorIDFeiE {
|
||||
if soundPercentage == 0 {
|
||||
@@ -969,43 +612,9 @@ func PKCS5UnPadding(origData []byte) []byte {
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
||||
|
||||
//合成水印图
|
||||
func MixWatermarkImg(imgWatermark, img string, exPrefixBegin, exPrefixEnd *time.Time) (imgMix string) {
|
||||
if exPrefixBegin != nil && exPrefixEnd != nil {
|
||||
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 {
|
||||
baseURL := base64.URLEncoding.EncodeToString([]byte(imgWatermark))
|
||||
var imgUrl string
|
||||
if strings.Contains(img, "?") {
|
||||
imgUrl = img + "/imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/Center/dx/0/dy/0"
|
||||
} else {
|
||||
imgUrl = img + "?imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/Center/dx/0/dy/0"
|
||||
}
|
||||
if resBinary, _, err := DownloadFileByURL(imgUrl); err == nil {
|
||||
if downloadURL, err := UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix())+img[strings.LastIndex(img, "/")+1:len(img)]); err == nil {
|
||||
if err == nil {
|
||||
return downloadURL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 {
|
||||
return imgMix
|
||||
}
|
||||
}
|
||||
return imgMix
|
||||
}
|
||||
|
||||
func GetDefendPriceIssue() (issue int) {
|
||||
if time.Now().Hour() >= 22 {
|
||||
issue = utils.Str2Int(time.Now().AddDate(0, 0, 1).Format("20060102"))
|
||||
} else {
|
||||
issue = utils.Str2Int(time.Now().Format("20060102"))
|
||||
}
|
||||
return issue
|
||||
}
|
||||
|
||||
func GetLastDefendPriceIssue() (issue int) {
|
||||
return utils.Str2Int(time.Now().AddDate(0, 0, 1).Format("20060102"))
|
||||
func GetIssue() (issue int) {
|
||||
year, month, _ := time.Now().Date()
|
||||
return year*100 + int(month)
|
||||
}
|
||||
|
||||
//根据一堆坐标求面积
|
||||
@@ -1037,3 +646,75 @@ func polarTriangleArea(tan1, lng1, tan2, lng2 float64) (s float64) {
|
||||
t := tan1 * tan2
|
||||
return 2 * math.Atan2(t*math.Sin(deltaLng), 1+t*math.Cos(deltaLng))
|
||||
}
|
||||
|
||||
func GenRandomString(l int) string {
|
||||
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
bytes := []byte(str)
|
||||
result := []byte{}
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < l; i++ {
|
||||
result = append(result, bytes[r.Intn(len(bytes))])
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func GetDayTime() (dayTimeBegin, dayTimeEnd time.Time) {
|
||||
dayTimeBegin = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + " 00:00:00")
|
||||
dayTimeEnd = dayTimeBegin.AddDate(0, 0, 1)
|
||||
return dayTimeBegin, dayTimeEnd
|
||||
}
|
||||
|
||||
func GetWeekTime() (weekTimeBegin, weekTimeEnd time.Time) {
|
||||
offset := int(time.Now().Weekday() - 1)
|
||||
if offset == -1 {
|
||||
offset = -6
|
||||
}
|
||||
weekTimeBegin = time.Now().AddDate(0, 0, offset)
|
||||
weekTimeEnd = weekTimeBegin.AddDate(0, 0, 7)
|
||||
return weekTimeBegin, weekTimeEnd
|
||||
}
|
||||
|
||||
func BuildErr(errs []error) (err error) {
|
||||
var errStr = strings.Builder{}
|
||||
for _, v := range errs {
|
||||
errStr.WriteString(v.Error())
|
||||
}
|
||||
return fmt.Errorf(errStr.String())
|
||||
}
|
||||
|
||||
func SplitFlowAndUnit(flowStr string) (flow float64, unit string) {
|
||||
for _, v := range flowUnitMap {
|
||||
if strings.Contains(flowStr, v) {
|
||||
return utils.Str2Float64WithDefault(flowStr[:len(flowStr)-2], 0), flowStr[len(flowStr)-2:]
|
||||
}
|
||||
}
|
||||
return flow, unit
|
||||
}
|
||||
|
||||
func Flow2KB(flow float64, unit string) (flowKB float64) {
|
||||
if unit == "KB" {
|
||||
return flow
|
||||
} else if unit == "MB" {
|
||||
return flow * 1024
|
||||
} else if unit == "GB" {
|
||||
return flow * 1024 * 1024
|
||||
}
|
||||
return flowKB
|
||||
}
|
||||
|
||||
func FlowKB2Other(flowKB float64) (flow float64, unit string) {
|
||||
if flowKB < 1024 {
|
||||
return flowKB, "KB"
|
||||
} else {
|
||||
flowMB := math.Round(flowKB / float64(1024))
|
||||
if flowMB < 1024 {
|
||||
return flowMB, "MB"
|
||||
} else {
|
||||
flowGB := math.Round(flowMB / float64(1024))
|
||||
if flowGB < 1024 {
|
||||
return flowGB, "GB"
|
||||
}
|
||||
}
|
||||
}
|
||||
return flow, unit
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package jxutils
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
type ActStoreSkuMap struct {
|
||||
actStoreSkuMap map[int64]map[int]*model.ActStoreSku2
|
||||
}
|
||||
|
||||
// isActPrice为true表示是活动,false表示是结算
|
||||
func NewActStoreSkuMap(actStoreSkuList []*model.ActStoreSku2, isActPrice bool) (actMap *ActStoreSkuMap) {
|
||||
actMap = &ActStoreSkuMap{}
|
||||
actStoreSkuMap := make(map[int64]map[int]*model.ActStoreSku2)
|
||||
for _, v := range actStoreSkuList {
|
||||
index := Combine2Int(v.StoreID, v.SkuID)
|
||||
if actStoreSkuMap[index] == nil {
|
||||
actStoreSkuMap[index] = make(map[int]*model.ActStoreSku2)
|
||||
}
|
||||
if (isActPrice && v.ActualActPrice > 0 && (actStoreSkuMap[index][v.VendorID] == nil || actStoreSkuMap[index][v.VendorID].ActualActPrice > v.ActualActPrice)) ||
|
||||
(!isActPrice && v.EarningPrice > 0 && (actStoreSkuMap[index][v.VendorID] == nil || actStoreSkuMap[index][v.VendorID].EarningPrice > v.EarningPrice)) {
|
||||
actStoreSkuMap[index][v.VendorID] = v
|
||||
}
|
||||
}
|
||||
actMap.actStoreSkuMap = actStoreSkuMap
|
||||
return actMap
|
||||
}
|
||||
|
||||
func (a *ActStoreSkuMap) GetActStoreSku(storeID, skuID, vendorID int) (storeSku *model.ActStoreSku2) {
|
||||
index := Combine2Int(storeID, skuID)
|
||||
if a.actStoreSkuMap[index] != nil {
|
||||
if vendorID < 0 {
|
||||
for k := range a.actStoreSkuMap[index] {
|
||||
vendorID = k
|
||||
break
|
||||
}
|
||||
}
|
||||
storeSku = a.actStoreSkuMap[index][vendorID]
|
||||
}
|
||||
return storeSku
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user