Compare commits

...

197 Commits

Author SHA1 Message Date
momo
b9b7309edc Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 18:47:08 +08:00
momo
d22be1d676 fix:支付 2023-09-26 18:46:44 +08:00
laodaming
2d0b23e063 fix 2023-09-26 18:38:36 +08:00
laodaming
01b78a099a fix 2023-09-26 18:35:27 +08:00
momo
fcfea291e5 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 18:21:13 +08:00
momo
9c08acc97a fix:支付 2023-09-26 18:20:48 +08:00
momo
1203c087d8 fix:支付 2023-09-26 18:18:48 +08:00
eson
91c1c580f9 info get profile 2023-09-26 18:03:29 +08:00
eson
b571b1b31c info get profile 2023-09-26 17:57:54 +08:00
eson
62565fac4e Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-26 17:45:12 +08:00
eson
54613f5be0 info get profile 2023-09-26 17:45:07 +08:00
momo
dd8b864a7f Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 17:32:30 +08:00
momo
8d3fce919f fix:支付 2023-09-26 17:32:21 +08:00
eson
c880cba0a3 info get profile 2023-09-26 17:21:01 +08:00
eson
194dc50eaa info get profile 2023-09-26 17:20:44 +08:00
momo
ee6e31473e Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 17:18:20 +08:00
momo
0989faf35a fix:支付 2023-09-26 17:18:04 +08:00
eson
93b0cadea9 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-26 17:16:15 +08:00
eson
f387e46977 info get profile 2023-09-26 17:16:10 +08:00
momo
c46d9d8fd9 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 17:12:27 +08:00
momo
ad01dbc0e5 fix:支付 2023-09-26 17:12:12 +08:00
laodaming
26389bf4d6 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 17:08:56 +08:00
laodaming
15888a953b fix 2023-09-26 17:08:49 +08:00
momo
2c995e9512 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 17:04:45 +08:00
momo
44fd4f03e3 fix:支付 2023-09-26 17:04:27 +08:00
laodaming
76f4a682ac fix 2023-09-26 17:01:31 +08:00
momo
9e6f919fa8 fix:支付 2023-09-26 16:53:34 +08:00
laodaming
e2508cc347 fix 2023-09-26 16:40:13 +08:00
laodaming
d07350969f fix 2023-09-26 16:36:35 +08:00
momo
6e9f47ff85 fix:支付 2023-09-26 16:30:51 +08:00
laodaming
42bd585fe9 fix 2023-09-26 16:20:53 +08:00
momo
f20b4fad3e fix:支付 2023-09-26 16:16:58 +08:00
laodaming
871a7a278b Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 15:30:20 +08:00
momo
83dc607ec4 fix:支付 2023-09-26 15:29:33 +08:00
laodaming
fae365d59e Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 15:28:27 +08:00
laodaming
821cbb8879 fix 2023-09-26 15:28:17 +08:00
momo
821e36281a fix:支付 2023-09-26 15:25:05 +08:00
momo
ef522551e4 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 15:14:12 +08:00
momo
c7a2cf7d1c fix:支付 2023-09-26 15:14:08 +08:00
eson
4dfeebeaed Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-26 15:02:13 +08:00
eson
31debda97f info update profile 2023-09-26 15:02:09 +08:00
laodaming
a1d78b7a0c fix 2023-09-26 14:56:32 +08:00
laodaming
03cbe2894e fix 2023-09-26 14:48:49 +08:00
laodaming
82fc0f2b80 fix 2023-09-26 14:46:12 +08:00
laodaming
2747c9ddd9 fix 2023-09-26 14:38:34 +08:00
laodaming
d45a0eb680 fix 2023-09-26 14:23:09 +08:00
momo
4cd2e1ce65 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 13:54:51 +08:00
momo
00b3a974f9 fix:支付 2023-09-26 13:54:39 +08:00
eson
f9595aad3f info fix table 2023-09-26 13:31:42 +08:00
eson
85cd2bff8d Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-26 13:23:55 +08:00
eson
1e444ca616 info delete table 2023-09-26 13:23:49 +08:00
laodaming
1543e60301 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 13:06:59 +08:00
laodaming
600a6edd7b fix 2023-09-26 13:06:51 +08:00
eson
407ba29319 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-26 12:24:14 +08:00
eson
c42c37f65e info address 2023-09-26 12:24:09 +08:00
momo
cdeec5a4e1 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 12:21:30 +08:00
momo
94088b5aa4 fix:支付 2023-09-26 12:21:26 +08:00
laodaming
e23ee6518d fix 2023-09-26 12:12:50 +08:00
eson
79120e1fd9 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-26 12:08:57 +08:00
eson
6a41be4f3a info address 2023-09-26 12:08:51 +08:00
laodaming
f7992279e2 fix 2023-09-26 11:47:31 +08:00
laodaming
01cc115a60 fix 2023-09-26 11:40:27 +08:00
eson
47a1ecfc79 info address 2023-09-26 11:32:43 +08:00
eson
55a4526536 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-26 11:21:48 +08:00
eson
7eab65be87 info address 2023-09-26 11:21:43 +08:00
laodaming
fc302ad1be Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 11:11:58 +08:00
eson
87c2d7bf96 info address 2023-09-26 11:11:34 +08:00
laodaming
27f429cdec Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 11:11:27 +08:00
laodaming
f615e4fe77 fix 2023-09-26 11:10:41 +08:00
eson
87ff25a2e6 info address 2023-09-26 11:08:32 +08:00
eson
a832a6fa81 info address 2023-09-26 11:07:45 +08:00
eson
0e282e741b info address 2023-09-26 11:06:37 +08:00
eson
d0323646c5 info address 2023-09-26 11:05:31 +08:00
eson
2331979b65 info address 2023-09-26 11:04:12 +08:00
eson
c12675698b info address 2023-09-26 11:01:42 +08:00
eson
abdf8a43e7 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-26 10:58:28 +08:00
eson
3bba720f67 info address 2023-09-26 10:58:24 +08:00
momo
46f3b2ff0e Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-26 10:57:08 +08:00
momo
6c2fba2b3a fix:支付 2023-09-26 10:56:57 +08:00
laodaming
916e050585 fix 2023-09-26 10:54:11 +08:00
eson
5b3e3f047e info address 2023-09-26 10:45:53 +08:00
b03e2d020f info address 2023-09-26 00:02:50 +08:00
laodaming
cb9b8ed6fd Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-25 18:44:54 +08:00
laodaming
7490a3b324 fix 2023-09-25 18:44:47 +08:00
eson
3f4b341c33 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-25 18:42:53 +08:00
eson
cef9dfa34d info 2023-09-25 18:42:45 +08:00
momo
95cbaea69a fix:支付 2023-09-25 18:28:53 +08:00
momo
17b98f83ff fix:支付 2023-09-25 17:35:02 +08:00
momo
4261a5a97d fix:支付 2023-09-25 17:31:42 +08:00
laodaming
91acf4d2bc fix 2023-09-25 17:22:58 +08:00
laodaming
f713124154 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-25 17:21:37 +08:00
laodaming
4bbe9aaaa3 fix 2023-09-25 17:20:44 +08:00
momo
07185fdb46 fix:支付 2023-09-25 17:17:09 +08:00
momo
178cda5402 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-25 17:06:35 +08:00
momo
3c094cf201 fix:支付 2023-09-25 17:06:12 +08:00
eson
66084f9e96 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-25 16:01:34 +08:00
eson
c1203e8989 info 2023-09-25 16:01:28 +08:00
momo
5be1edfa71 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-25 16:01:03 +08:00
momo
6005f20c5e fix:支付 2023-09-25 16:00:50 +08:00
eson
8fe6e8be74 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-25 15:58:40 +08:00
eson
f2a0c7608e info 2023-09-25 15:58:33 +08:00
laodaming
29c7dc54e3 fix 2023-09-25 15:49:59 +08:00
laodaming
d8d91e9270 fix 2023-09-25 11:34:53 +08:00
laodaming
02b3788dc9 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-25 11:17:03 +08:00
laodaming
a7f21da8da fix 2023-09-25 11:16:55 +08:00
momo
287ee4db37 fix:支付 2023-09-22 17:39:20 +08:00
momo
0a4368ba7f Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 17:32:30 +08:00
momo
656d5038fe fix:支付 2023-09-22 17:32:23 +08:00
laodaming
c34811df83 fix 2023-09-22 17:21:40 +08:00
laodaming
98bc6294e6 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 17:04:08 +08:00
laodaming
2054b9ec97 fix 2023-09-22 17:04:01 +08:00
momo
b398da58e1 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 16:27:21 +08:00
momo
7e400ed761 fix:支付 2023-09-22 16:27:17 +08:00
laodaming
bea1fd230a Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 15:52:40 +08:00
laodaming
a2b7bfb253 fix 2023-09-22 15:52:32 +08:00
eson
646c04eba9 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 15:52:26 +08:00
eson
1bd2b83bca info 2023-09-22 15:52:20 +08:00
laodaming
d6134a7407 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 15:43:49 +08:00
laodaming
c3011e87eb fix 2023-09-22 15:43:42 +08:00
eson
e811bf3e4a Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 15:42:15 +08:00
eson
b3ed5703a8 info 2023-09-22 15:42:09 +08:00
laodaming
f6e073bb41 fix 2023-09-22 15:24:16 +08:00
laodaming
b6651c4bdc fix 2023-09-22 15:19:41 +08:00
laodaming
bfea40c643 fix 2023-09-22 15:12:44 +08:00
laodaming
c8a52321a5 fix 2023-09-22 15:00:08 +08:00
laodaming
129583d19a fix 2023-09-22 14:57:56 +08:00
laodaming
c2bb174574 fix 2023-09-22 14:44:55 +08:00
laodaming
551f9083e9 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 14:38:32 +08:00
laodaming
c36c8ab6f9 fix 2023-09-22 14:38:26 +08:00
eson
6fd3bc8a3b Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 14:34:46 +08:00
eson
4005af2040 info 2023-09-22 14:34:23 +08:00
laodaming
20150a81b5 fix 2023-09-22 14:33:16 +08:00
laodaming
e4c165cd18 fix 2023-09-22 14:29:21 +08:00
laodaming
366a441cf2 fix 2023-09-22 14:14:04 +08:00
eson
ec4fe76856 info 2023-09-22 13:37:23 +08:00
eson
173fa23e80 info 2023-09-22 13:35:05 +08:00
eson
b6e994844e info 2023-09-22 13:21:06 +08:00
eson
9a4899558e info 2023-09-22 13:18:31 +08:00
eson
b1675ae0bf info 2023-09-22 13:14:53 +08:00
eson
8b81308bd2 info 2023-09-22 12:31:24 +08:00
eson
cc7d7361d4 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 12:28:42 +08:00
eson
730491ffed info 2023-09-22 12:28:38 +08:00
laodaming
9753920595 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 12:15:23 +08:00
laodaming
2fc914214c fix 2023-09-22 12:15:16 +08:00
momo
ddb4ec944d Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 12:12:44 +08:00
momo
c2723861fa fix:支付 2023-09-22 12:12:33 +08:00
eson
c82ae399b7 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 12:09:47 +08:00
eson
c163cfe234 info 2023-09-22 12:09:41 +08:00
laodaming
72e75e7858 fix 2023-09-22 12:05:20 +08:00
laodaming
c9af4fb420 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 12:05:17 +08:00
laodaming
27ae48991c fix 2023-09-22 12:05:05 +08:00
eson
65a7d530cc Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 12:03:11 +08:00
eson
7866a5a369 proxyserver 2023-09-22 12:03:04 +08:00
laodaming
0dcaf2ce09 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 11:59:44 +08:00
laodaming
dd6b80ee71 fix 2023-09-22 11:59:37 +08:00
eson
4c944c8c72 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 11:55:45 +08:00
eson
e29e8d8049 proxyserver 2023-09-22 11:55:39 +08:00
laodaming
e1094b9be6 fix 2023-09-22 11:47:32 +08:00
eson
fc50bf587f Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 11:46:02 +08:00
eson
11cee190b0 nacos config 2023-09-22 11:45:56 +08:00
laodaming
21c4907e44 fix 2023-09-22 11:37:44 +08:00
laodaming
951635e7f8 fix 2023-09-22 11:36:38 +08:00
laodaming
2a849dde38 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 11:36:16 +08:00
laodaming
caf2f753a5 fix 2023-09-22 11:36:10 +08:00
eson
2d224c0d67 nacos config 2023-09-22 11:35:40 +08:00
eson
e925d8c684 nacos config 2023-09-22 11:32:16 +08:00
eson
a6a40a2ad5 nacos config 2023-09-22 11:31:39 +08:00
eson
baa0cc1644 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 11:27:24 +08:00
eson
db7d53532a nacos config 2023-09-22 11:27:19 +08:00
laodaming
6985b76e49 fix 2023-09-22 11:25:51 +08:00
laodaming
745cea9617 fix 2023-09-22 11:22:32 +08:00
momo
d00089c625 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 11:01:03 +08:00
momo
0f7514b5bd fix:支付 2023-09-22 11:00:54 +08:00
eson
95cd86d103 Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 10:53:10 +08:00
eson
85b391a4d2 nacos config 2023-09-22 10:53:05 +08:00
laodaming
e2db17c326 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 10:49:15 +08:00
laodaming
741963275e fix 2023-09-22 10:49:07 +08:00
eson
541627183b Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop 2023-09-22 10:44:09 +08:00
eson
cd6a919145 nacos config 2023-09-22 10:44:04 +08:00
laodaming
bb645ce6f6 fix 2023-09-22 10:41:38 +08:00
momo
1040f21ca6 Merge branch 'develop' of gitee.com:fusenpack/fusenapi into develop 2023-09-22 10:39:09 +08:00
momo
fead7c6ae9 fix:支付 2023-09-22 10:39:02 +08:00
eson
15f589c09d nacos config 2023-09-22 10:37:34 +08:00
c4b4b72947 fix 2023-09-22 00:46:05 +08:00
99f785a7c3 fix 2023-09-22 00:35:10 +08:00
c280a661a1 fix 2023-09-22 00:31:58 +08:00
b37c2094ed fix 2023-09-22 00:28:35 +08:00
e6470719bb fix 2023-09-22 00:22:53 +08:00
6260d29dc7 fix 2023-09-22 00:21:18 +08:00
7aa4a57257 fix 2023-09-22 00:18:04 +08:00
7324aabbd6 fix 2023-09-22 00:12:23 +08:00
0b8f6e69cf fix 2023-09-22 00:03:01 +08:00
bd1b6ee23e fix 2023-09-21 23:59:01 +08:00
58e2068170 fix 2023-09-21 23:47:34 +08:00
45ef0b8bc9 fix 2023-09-21 23:39:15 +08:00
ff011f6452 fix 2023-09-21 23:32:58 +08:00
d3c96184b8 fix 2023-09-21 23:21:57 +08:00
93 changed files with 2806 additions and 1299 deletions

2
.gitignore vendored
View File

@ -45,3 +45,5 @@ shared-state
*.zip *.zip
vendor vendor
grpc_server/gen

View File

@ -3,7 +3,7 @@ package constants
// 订单类型 // 订单类型
const ( const (
DELIVERYMETHODDIRECTMAIL int64 = 1 DELIVERYMETHODDIRECTMAIL int64 = 1
DELIVERYMETHODDSCLOUDSTORE int64 = 1 DELIVERYMETHODDSCLOUDSTORE int64 = 2
) )
// 货币 // 货币
@ -23,7 +23,7 @@ type ExchangeRateUnit interface{}
type PayMethods string type PayMethods string
const ( const (
PAYMETHODCARD PayMethods = "CARD" PAY_METHOD_CARD PayMethods = "CARD"
PayMethodVISA PayMethods = "VISA" PayMethodVISA PayMethods = "VISA"
) )
@ -56,18 +56,21 @@ const (
type OrderStatusCode int64 type OrderStatusCode int64
const ( const (
ORDERSTATUSUNPAIDDEPOSIT OrderStatusCode = 0 // 0,未支付定金 ORDER_STATUS_UNPAIDDEPOSIT OrderStatusCode = 0 // 0,未支付定金
ORDERSTATUSDIRECTMAILORDERED OrderStatusCode = 10100 // 10100,直邮单--已下单 ORDER_STATUS_DIRECTMAIL_ORDERED OrderStatusCode = 10100 // 10100,直邮单--已下单
ORDERSTATUSDIRECTMAILCANCEL OrderStatusCode = 10101 // 10101,直邮单--已取消 ORDER_STATUS_DIRECTMAIL_ORDEREDMAINING OrderStatusCode = 10100001 // 10100001,直邮单--已下单--尾款
ORDERSTATUSDIRECTMAILSTARTPRODUCTION OrderStatusCode = 10200 // 10200,直邮单--开始生产 ORDER_STATUS_DIRECTMAIL_CANCEL OrderStatusCode = 10101 // 10101,直邮单--已取消
ORDERSTATUSDIRECTMAILCOMPLETEPRODUCTION OrderStatusCode = 10300 // 10300,直邮单--生产完成 ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION OrderStatusCode = 10200 // 10200,直邮单--开始生产
ORDERSTATUSDIRECTMAILSHIPPED OrderStatusCode = 10400 // 10400,直邮单--已发货 ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION OrderStatusCode = 10300 // 10300,直邮单--生产完成
ORDERSTATUSDIRECTMAILARRIVED OrderStatusCode = 10500 // 10500,直邮单--已到达 ORDER_STATUS_DIRECTMAIL_SHIPPED OrderStatusCode = 10400 // 10400,直邮单--已发货
ORDERSTATUSCLOUDSTOREORDERED OrderStatusCode = 20100 // 20100,云仓单--已下单 ORDER_STATUS_DIRECTMAIL_ARRIVED OrderStatusCode = 10500 // 10500,直邮单--已到达
ORDERSTATUSCLOUDSTORECANCEL OrderStatusCode = 20101 // 20101,云仓单--已取消 ORDER_STATUS_CLOUDSTORE_ORDERED OrderStatusCode = 20100 // 20100,云仓单--已下单
ORDERSTATUSCLOUDSTORESTARTPRODUCTION OrderStatusCode = 20200 // 20200,云仓单--开始生产 ORDER_STATUS_CLOUDSTORE_ORDEREDMAINING OrderStatusCode = 20100001 // 20100001,云仓单--已下单-尾款
ORDERSTATUSCLOUDSTOREOMPLETEPRODUCTION OrderStatusCode = 20300 // 20300,云仓单--生产完成 ORDER_STATUS_CLOUDSTORE_CANCEL OrderStatusCode = 20101 // 20101,云仓单--已取消
ORDERSTATUSCLOUDSTOREARRIVEDWAREHOUSE OrderStatusCode = 20400 // 20400,云仓单--直达仓库 ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION OrderStatusCode = 20200 // 20200,云仓单--开始生产
ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION OrderStatusCode = 20300 // 20300,云仓单--生产完成
ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE OrderStatusCode = 20400 // 20400,云仓单--直达仓库
ORDER_STATUS_COMPLETE OrderStatusCode = 30000 // 30000,订单完成
) )
// 订单状态名称 // 订单状态名称
@ -85,33 +88,35 @@ var OrderStatusUserCLOUDSTORE []OrderStatusCode
func init() { func init() {
// 订单状态名称 // 订单状态名称
PayStatusMessage = make(map[PayStatusCode]string) PayStatusMessage = make(map[PayStatusCode]string)
PayStatusMessage[PAYSTATUSUNPAID] = "Paid" PayStatusMessage[PAYSTATUSUNPAID] = "Unpaid"
PayStatusMessage[PAYSTATUSPAID] = "Unpaid" PayStatusMessage[PAYSTATUSPAID] = "Paid"
PayStatusMessage[PAYSTATUSREFUNDED] = "Refunded" PayStatusMessage[PAYSTATUSREFUNDED] = "Refunded"
// 订单状态名称 // 订单状态名称
OrderStatusMessage = make(map[OrderStatusCode]string) OrderStatusMessage = make(map[OrderStatusCode]string)
OrderStatusMessage[ORDERSTATUSUNPAIDDEPOSIT] = "未支付定金" OrderStatusMessage[ORDER_STATUS_UNPAIDDEPOSIT] = "未支付定金"
OrderStatusMessage[ORDERSTATUSDIRECTMAILORDERED] = "直邮单--已下单" OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ORDERED] = "直邮单--已下单"
OrderStatusMessage[ORDERSTATUSDIRECTMAILSTARTPRODUCTION] = "直邮单--开始生产" OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION] = "直邮单--开始生产"
OrderStatusMessage[ORDERSTATUSDIRECTMAILCOMPLETEPRODUCTION] = "直邮单--生产完成" OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION] = "直邮单--生产完成"
OrderStatusMessage[ORDERSTATUSDIRECTMAILSHIPPED] = "直邮单--已发货" OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_SHIPPED] = "直邮单--已发货"
OrderStatusMessage[ORDERSTATUSDIRECTMAILARRIVED] = "直邮单--已到达" OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ARRIVED] = "直邮单--已到达"
OrderStatusMessage[ORDERSTATUSCLOUDSTOREORDERED] = "云仓单--已下单" OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ORDERED] = "云仓单--已下单"
OrderStatusMessage[ORDERSTATUSCLOUDSTORESTARTPRODUCTION] = "云仓单--开始生产" OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION] = "云仓单--开始生产"
OrderStatusMessage[ORDERSTATUSCLOUDSTOREOMPLETEPRODUCTION] = "云仓单--生产完成" OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION] = "云仓单--生产完成"
OrderStatusMessage[ORDERSTATUSCLOUDSTOREARRIVEDWAREHOUSE] = "云仓单--直达仓库" OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE] = "云仓单--直达仓库"
OrderStatusMessage[ORDER_STATUS_COMPLETE] = "订单完成"
// 订单状态--用户可见--直邮 // 订单状态--用户可见--直邮
OrderStatusUserDIRECTMAIL = []OrderStatusCode{ OrderStatusUserDIRECTMAIL = []OrderStatusCode{
ORDERSTATUSUNPAIDDEPOSIT, ORDER_STATUS_UNPAIDDEPOSIT, ORDER_STATUS_COMPLETE,
ORDERSTATUSDIRECTMAILORDERED, ORDERSTATUSDIRECTMAILSTARTPRODUCTION, ORDERSTATUSDIRECTMAILCOMPLETEPRODUCTION, ORDERSTATUSDIRECTMAILSHIPPED, ORDERSTATUSDIRECTMAILARRIVED, ORDER_STATUS_DIRECTMAIL_ORDERED, ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION, ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION, ORDER_STATUS_DIRECTMAIL_SHIPPED, ORDER_STATUS_DIRECTMAIL_ARRIVED,
} }
// 订单状态--用户可见--云仓 // 订单状态--用户可见--云仓
OrderStatusUserCLOUDSTORE = []OrderStatusCode{ OrderStatusUserCLOUDSTORE = []OrderStatusCode{
ORDERSTATUSUNPAIDDEPOSIT, ORDER_STATUS_UNPAIDDEPOSIT, ORDER_STATUS_COMPLETE,
ORDERSTATUSCLOUDSTOREORDERED, ORDERSTATUSCLOUDSTORESTARTPRODUCTION, ORDERSTATUSCLOUDSTOREOMPLETEPRODUCTION, ORDERSTATUSCLOUDSTOREARRIVEDWAREHOUSE, ORDER_STATUS_CLOUDSTORE_ORDERED, ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION, ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION, ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE,
} }
} }

View File

@ -5,3 +5,11 @@ username: ...
password: ... password: ...
namespace: fs_server_api_dev namespace: fs_server_api_dev
group: FS-SERVER-API group: FS-SERVER-API
proxyserver:
key: /opt/server.dev.fusenpack.com.key
pem: /opt/server.dev.fusenpack.com.pem
serverbackend:
key: /opt/serverbackend.dev.fusenpack.com.key
pem: /opt/serverbackend.dev.fusenpack.com.pem

2
go.mod
View File

@ -18,7 +18,7 @@ require (
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/streadway/amqp v1.1.0 github.com/streadway/amqp v1.1.0
github.com/stripe/stripe-go/v74 v74.26.0 github.com/stripe/stripe-go/v75 v75.7.0
github.com/zeromicro/go-zero v1.5.4 github.com/zeromicro/go-zero v1.5.4
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
golang.org/x/oauth2 v0.10.0 golang.org/x/oauth2 v0.10.0

4
go.sum
View File

@ -548,8 +548,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stripe/stripe-go/v74 v74.26.0 h1:enbhLtjKGWvJKcGM0f2CazqFSXzpHXcQ42nG2PNsWK0= github.com/stripe/stripe-go/v75 v75.7.0 h1:Zk7trlj0kClZOwnpjGz7FgVQRBI0Koi28/eaNATgAs0=
github.com/stripe/stripe-go/v74 v74.26.0/go.mod h1:f9L6LvaXa35ja7eyvP6GQswoaIPaBRvGAimAO+udbBw= github.com/stripe/stripe-go/v75 v75.7.0/go.mod h1:wT44gah+eCY8Z0aSpY/vQlYYbicU9uUAbAqdaUxxDqE=
github.com/tidwall/gjson v1.12.0 h1:61wEp/qfvFnqKH/WCI3M8HuRut+mHT6Mr82QrFmM2SY= github.com/tidwall/gjson v1.12.0 h1:61wEp/qfvFnqKH/WCI3M8HuRut+mHT6Mr82QrFmM2SY=
github.com/tidwall/gjson v1.12.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.12.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=

View File

@ -2,13 +2,14 @@ package gmodel
import ( import (
"gorm.io/gorm" "gorm.io/gorm"
"time"
) )
// fs_address 用户地址表 // fs_address 用户地址表
type FsAddress struct { type FsAddress struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // AddressId int64 `gorm:"primary_key;default:0;auto_increment;" json:"address_id"` //
UserId *int64 `gorm:"index;default:0;" json:"user_id"` // 用户ID UserId *int64 `gorm:"index;default:0;" json:"user_id"` // 用户ID
Name *string `gorm:"default:'';" json:"name"` // 地址名称 AddressName *string `gorm:"default:'';" json:"address_name"` //
FirstName *string `gorm:"default:'';" json:"first_name"` // FirstName FirstName *string `gorm:"default:'';" json:"first_name"` // FirstName
LastName *string `gorm:"default:'';" json:"last_name"` // LastName LastName *string `gorm:"default:'';" json:"last_name"` // LastName
Mobile *string `gorm:"default:'';" json:"mobile"` // 手机号码 Mobile *string `gorm:"default:'';" json:"mobile"` // 手机号码
@ -20,6 +21,9 @@ type FsAddress struct {
ZipCode *string `gorm:"default:'';" json:"zip_code"` // ZipCode *string `gorm:"default:'';" json:"zip_code"` //
Status *int64 `gorm:"default:0;" json:"status"` // 1正常 0异常 Status *int64 `gorm:"default:0;" json:"status"` // 1正常 0异常
IsDefault *int64 `gorm:"index;default:0;" json:"is_default"` // 1默认地址0非默认地址 IsDefault *int64 `gorm:"index;default:0;" json:"is_default"` // 1默认地址0非默认地址
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // 创建时间
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // 更新时间
Ltime *time.Time `gorm:"index;default:'0000-00-00 00:00:00';" json:"ltime"` // 上次被使用的时间
} }
type FsAddressModel struct { type FsAddressModel struct {
db *gorm.DB db *gorm.DB

View File

@ -2,17 +2,19 @@ package gmodel
import ( import (
"context" "context"
"time"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm" "gorm.io/gorm"
) )
func (a *FsAddressModel) GetOne(ctx context.Context, id int64, userId int64) (resp *FsAddress, err error) { func (a *FsAddressModel) GetOne(ctx context.Context, addressId int64, userId int64) (resp *FsAddress, err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`id` = ? and `user_id` = ? and `status` = ? ", id, userId, 1).Take(&resp).Error err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`address_id` = ? and `user_id` = ? and `status` = ? ", addressId, userId, 1).Take(&resp).Error
return resp, err return resp, err
} }
func (a *FsAddressModel) GetUserAllAddress(ctx context.Context, userId int64) (resp []FsAddress, err error) { func (a *FsAddressModel) GetUserAllAddress(ctx context.Context, userId int64) (resp []FsAddress, err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`user_id` = ? and `status` = ?", userId, 1).Order("`id` DESC").Find(&resp).Error err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`user_id` = ? and `status` = ?", userId, 1).Order("`ltime` DESC").Find(&resp).Error
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -21,11 +23,11 @@ func (a *FsAddressModel) GetUserAllAddress(ctx context.Context, userId int64) (r
func (a *FsAddressModel) CreateOne(ctx context.Context, address *FsAddress) (result *FsAddress, err error) { func (a *FsAddressModel) CreateOne(ctx context.Context, address *FsAddress) (result *FsAddress, err error) {
err = a.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
// now := time.Now().UTC().Unix() now := time.Now().UTC()
result = &FsAddress{ result = &FsAddress{
UserId: address.UserId, UserId: address.UserId,
Name: address.Name, AddressName: address.AddressName,
FirstName: address.FirstName, FirstName: address.FirstName,
LastName: address.LastName, LastName: address.LastName,
Mobile: address.Mobile, Mobile: address.Mobile,
@ -37,9 +39,26 @@ func (a *FsAddressModel) CreateOne(ctx context.Context, address *FsAddress) (res
ZipCode: address.ZipCode, ZipCode: address.ZipCode,
Status: address.Status, Status: address.Status,
IsDefault: address.IsDefault, IsDefault: address.IsDefault,
Ctime: &now,
Utime: &now,
Ltime: &now,
} }
return tx.Create(result).Error // lastOne := &FsAddress{}
// err = tx.Where("user_id = ?", lastOne.UserId).Order("ltime ASC").Take(&lastOne).Error
// if err == gorm.ErrRecordNotFound {
// result.Ltime = &now
// return tx.Model(&FsAddress{}).Create(result).Error
// }
// if err != nil {
// return err
// }
// // 根据lastOne处理时间
// ltime := (*lastOne.Ltime).Add(-time.Second)
// result.Ltime = &ltime
return tx.Model(&FsAddress{}).Create(result).Error
}) })
if err != nil { if err != nil {
@ -49,15 +68,47 @@ func (a *FsAddressModel) CreateOne(ctx context.Context, address *FsAddress) (res
return result, nil return result, nil
} }
func (a *FsAddressModel) UpdateAddAddress(ctx context.Context, address *FsAddress) (err error) { func (a *FsAddressModel) UpdateAddress(ctx context.Context, address *FsAddress) (err error) {
err = a.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
if *address.IsDefault > 0 { err = tx.
err = tx.Model(&FsAddress{}).Where("user_id = ? and is_default = 1 ", address.UserId).Update("is_default", 0).Error Where("user_id = ? and address_id = ? and status = 1 ", address.UserId, address.AddressId).
Updates(address).Error
if err != nil { if err != nil {
return err return err
} }
} return err
return tx.Model(&FsAddress{}).Where("id = ? and user_id = ?", address.Id, address.UserId).Omit("id", "user_id").Updates(address).Error
}) })
return err return err
} }
func (a *FsAddressModel) SettingUserDefaultAddress(ctx context.Context, userId int64, addressId int64) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
now := time.Now().UTC()
err = tx.Model(&FsAddress{}).Where(" `user_id` = ? and `status` = ? and `address_id` = ? ", userId, 1, addressId).
UpdateColumn("ltime", now.AddDate(250, 0, 0)).
UpdateColumn("utime", now).Error
if err != nil {
return err
}
err = tx.Where(" `user_id` = ? and `status` = ? and `address_id` != ? and `ltime` > ? ", userId, 1, addressId, now.AddDate(10, 0, 0)).
UpdateColumn("ltime", now).Error
if err != nil {
logx.Error(err)
}
return nil
})
return
}
func (a *FsAddressModel) DeleteOne(ctx context.Context, addressId int64, userId int64) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).
Where("`address_id` = ? and `user_id` = ? and `status` = ? ", addressId, userId, 1).
UpdateColumn("status", 0).Error
return err
}

View File

@ -2,6 +2,7 @@ package gmodel
import ( import (
"gorm.io/gorm" "gorm.io/gorm"
"time"
) )
// fs_change_code 忘记密码code表 // fs_change_code 忘记密码code表
@ -9,7 +10,7 @@ type FsChangeCode struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id
Email *string `gorm:"default:'';" json:"email"` // Email *string `gorm:"default:'';" json:"email"` //
Code *string `gorm:"default:'';" json:"code"` // Code *string `gorm:"default:'';" json:"code"` //
CreatedAt *int64 `gorm:"default:0;" json:"created_at"` // 创建时间 Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
IsUse *int64 `gorm:"default:0;" json:"is_use"` // 是否使用 1已使用 0未使用 IsUse *int64 `gorm:"default:0;" json:"is_use"` // 是否使用 1已使用 0未使用
Metadata *[]byte `gorm:"default:'';" json:"metadata"` // Metadata *[]byte `gorm:"default:'';" json:"metadata"` //
Module *string `gorm:"default:'logo';" json:"module"` // Module *string `gorm:"default:'logo';" json:"module"` //

View File

@ -2,6 +2,7 @@ package gmodel
import ( import (
"gorm.io/gorm" "gorm.io/gorm"
"time"
) )
// fs_guest 游客表 // fs_guest 游客表
@ -10,12 +11,8 @@ type FsGuest struct {
AuthKey *string `gorm:"default:'';" json:"auth_key"` // jwt token AuthKey *string `gorm:"default:'';" json:"auth_key"` // jwt token
Status *int64 `gorm:"index;default:1;" json:"status"` // 1正常 0不正常 Status *int64 `gorm:"index;default:1;" json:"status"` // 1正常 0不正常
IsDel *int64 `gorm:"index;default:0;" json:"is_del"` // 是否删除 1删除 IsDel *int64 `gorm:"index;default:0;" json:"is_del"` // 是否删除 1删除
CreatedAt *int64 `gorm:"index;default:0;" json:"created_at"` // 添加时间 Ctime *time.Time `gorm:"index;default:'0000-00-00 00:00:00';" json:"ctime"` //
UpdatedAt *int64 `gorm:"default:0;" json:"updated_at"` // 更新时间 Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
IsOpenRender *int64 `gorm:"default:0;" json:"is_open_render"` // 是否打开个性化渲染1开启0关闭
IsThousandFace *int64 `gorm:"default:0;" json:"is_thousand_face"` // 是否已经存在千人千面1存在0不存在
IsLowRendering *int64 `gorm:"default:0;" json:"is_low_rendering"` // 是否开启低渲染模型渲染
IsRemoveBg *int64 `gorm:"default:1;" json:"is_remove_bg"` // 用户上传logo是否去除背景
} }
type FsGuestModel struct { type FsGuestModel struct {
db *gorm.DB db *gorm.DB

View File

@ -12,11 +12,11 @@ import (
func (m *FsGuestModel) GenerateGuestID(ctx context.Context, AccessSecret uint64) (authKey string, err error) { func (m *FsGuestModel) GenerateGuestID(ctx context.Context, AccessSecret uint64) (authKey string, err error) {
err = m.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { err = m.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
now := time.Now().UTC().Unix() now := time.Now().UTC()
var record = &FsGuest{} var record = &FsGuest{}
tx.Create(record) tx.Create(record)
authKey, err = auth.GenerateJwtTokenUint64(AccessSecret, now, 31536000, 0, int64(record.GuestId)) authKey, err = auth.GenerateJwtTokenUint64(AccessSecret, now.Unix(), 31536000, 0, int64(record.GuestId))
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
err = tx.Rollback().Error err = tx.Rollback().Error
@ -26,7 +26,7 @@ func (m *FsGuestModel) GenerateGuestID(ctx context.Context, AccessSecret uint64)
return err return err
} }
record.AuthKey = &authKey record.AuthKey = &authKey
record.CreatedAt = &now record.Ctime = &now
err = tx.Updates(record).Error err = tx.Updates(record).Error
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)

View File

@ -40,7 +40,7 @@ type PayInfo struct {
Metadata map[string]interface{} `json:"metadata"` // 额外参数 Metadata map[string]interface{} `json:"metadata"` // 额外参数
PayAmount AmountInfo `json:"pay_amount"` // 金额明细 PayAmount AmountInfo `json:"pay_amount"` // 金额明细
PayMethod string `json:"pay_method"` // 交易方式 PayMethod string `json:"pay_method"` // 交易方式
PayTime **time.Time `json:"pay_time"` // 支付时间 PayTime *time.Time `json:"pay_time"` // 支付时间
Status PayStatus `json:"status"` // 当前状态 Status PayStatus `json:"status"` // 当前状态
StatusLink []PayStatus `json:"status_link"` // 状态链路 StatusLink []PayStatus `json:"status_link"` // 状态链路
TradeNo string `json:"trade_no"` // 支付交易号 TradeNo string `json:"trade_no"` // 支付交易号
@ -95,23 +95,26 @@ type OrderStatus struct {
// 订单商品 // 订单商品
type OrderProduct struct { type OrderProduct struct {
TotalPrice AmountInfo `json:"amount"` // 商品总价 TotalPrice AmountInfo `json:"total_price"` // 商品总价
ExpectedDeliveryTime *time.Time `json:"expected_delivery_time"` // 预计到货时间 ExpectedDeliveryTime *time.Time `json:"expected_delivery_time"` // 预计到货时间
PurchaseQuantity int64 `json:"purchase_quantity"` // 购买数量 PurchaseQuantity PurchaseQuantity `json:"purchase_quantity"` // 购买数量
ProductID int64 `json:"product_id"` // 商品ID ProductID int64 `json:"product_id"` // 商品ID
ProductName string `json:"product_name"` // 商品名称 ProductName string `json:"product_name"` // 商品名称
ItemPrice AmountInfo `json:"product_price"` // 商品单价 ItemPrice AmountInfo `json:"item_price"` // 商品单价
ProductSnapshot interface{} `json:"product_snapshot"` // 商品快照 ProductSnapshot interface{} `json:"product_snapshot"` // 商品快照
ShoppingCartSnapshot *FsShoppingCart `json:"shopping_cart_snapshot"` // 购物车快照 ShoppingCartSnapshot *FsShoppingCartData `json:"shopping_cart_snapshot"` // 购物车快照
ProductCover string `json:"product_cover"` // 商品封面 ProductCover string `json:"product_cover"` // 商品封面
ProductCoverMetadata map[string]interface{} `json:"product_cover_metadata"` // 商品封面 ProductCoverMetadata map[string]interface{} `json:"product_cover_metadata"` // 商品封面
ProductSn string `json:"product_sn"` // 商品编码 ProductSn string `json:"product_sn"` // 商品编码
DiyInformation *UserDiyInformation `json:"diy_information"` DiyInformation *UserDiyInformation `json:"diy_information"`
SizeInfo *OrderProductSizeInfo `json:"size_info"` SizeInfo *OrderProductSizeInfo `json:"size_info"`
FittingInfo *OrderProductFittingInfo `json:"fitting_info"` FittingInfo *OrderProductFittingInfo `json:"fitting_info"`
StepNum []int `json:"step_num"` // 阶梯数量
IsHighlyCustomized int64 `json:"is_highly_customized"` IsHighlyCustomized int64 `json:"is_highly_customized"`
} }
type PurchaseQuantity struct {
Current interface{} `json:"current"`
Initiate interface{} `json:"initiate"`
}
type OrderProductSizeInfo struct { type OrderProductSizeInfo struct {
SizeID int64 `json:"size_id"` SizeID int64 `json:"size_id"`

View File

@ -36,6 +36,7 @@ type FsProduct struct {
RecommendProductSort *string `gorm:"default:'';" json:"recommend_product_sort"` // RecommendProductSort *string `gorm:"default:'';" json:"recommend_product_sort"` //
SceneIds *string `gorm:"default:'';" json:"scene_ids"` // SceneIds *string `gorm:"default:'';" json:"scene_ids"` //
IsCustomization *int64 `gorm:"default:0;" json:"is_customization"` // 是否可定制 IsCustomization *int64 `gorm:"default:0;" json:"is_customization"` // 是否可定制
Unit *string `gorm:"default:'';" json:"unit"` //
} }
type FsProductModel struct { type FsProductModel struct {
db *gorm.DB db *gorm.DB

View File

@ -2,6 +2,7 @@ package gmodel
import ( import (
"gorm.io/gorm" "gorm.io/gorm"
"time"
) )
// fs_product_model3d 产品模型表 // fs_product_model3d 产品模型表
@ -20,12 +21,15 @@ type FsProductModel3d struct {
PartId *int64 `gorm:"default:0;" json:"part_id"` // 配件选项id配件就是模型的id PartId *int64 `gorm:"default:0;" json:"part_id"` // 配件选项id配件就是模型的id
PartList *string `gorm:"default:'';" json:"part_list"` // PartList *string `gorm:"default:'';" json:"part_list"` //
Status *int64 `gorm:"default:0;" json:"status"` // 状态位 显示 删除 Status *int64 `gorm:"default:0;" json:"status"` // 状态位 显示 删除
Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间 Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
OptionTemplate *int64 `gorm:"default:0;" json:"option_template"` // 配件绑定的公共模板 OptionTemplate *int64 `gorm:"default:0;" json:"option_template"` // 配件绑定的公共模板
Price *int64 `gorm:"default:0;" json:"price"` // 仅配件用,配件的价格, 单位:美分 Price *int64 `gorm:"default:0;" json:"price"` //
Sku *string `gorm:"default:'';" json:"sku"` // sku Sku *string `gorm:"default:'';" json:"sku"` // sku
IsHot *int64 `gorm:"default:0;" json:"is_hot"` // 是否热门 IsHot *int64 `gorm:"default:0;" json:"is_hot"` // 是否热门
IsCloudRender *int64 `gorm:"default:0;" json:"is_cloud_render"` // 是否设置为云渲染模型 IsCloudRender *int64 `gorm:"default:0;" json:"is_cloud_render"` // 是否设置为云渲染模型
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
StepPrice *[]byte `gorm:"default:'';" json:"step_price"` //
PackedUnit *int64 `gorm:"default:0;" json:"packed_unit"` // 被打包的数量单位
} }
type FsProductModel3dModel struct { type FsProductModel3dModel struct {
db *gorm.DB db *gorm.DB

View File

@ -4,8 +4,19 @@ import (
"context" "context"
) )
// 阶梯价结构
type StepPriceJsonStruct struct {
PriceRange []struct {
Label string `json:"label"`
Price int64 `json:"price"`
EndQuantity int64 `json:"end_quantity"`
StartQuantity int64 `json:"start_quantity"`
} `json:"price_range"`
MinBuyUnitsNum int64 `json:"min_buy_units_num"`
}
func (d *FsProductModel3dModel) FindOne(ctx context.Context, id int64, fields ...string) (resp *FsProductModel3d, err error) { func (d *FsProductModel3dModel) FindOne(ctx context.Context, id int64, fields ...string) (resp *FsProductModel3d, err error) {
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` = ? ", id) db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` = ? and `status` =? ", id, 1)
if len(fields) > 0 { if len(fields) > 0 {
db = db.Select(fields[0]) db = db.Select(fields[0])
} }
@ -30,7 +41,7 @@ func (d *FsProductModel3dModel) GetAllByIdsWithoutStatus(ctx context.Context, id
if len(ids) == 0 { if len(ids) == 0 {
return return
} }
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?)", ids) db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?) and `status` = ?", ids, 1)
if len(fields) > 0 { if len(fields) > 0 {
db = db.Select(fields[0]) db = db.Select(fields[0])
} }
@ -69,13 +80,13 @@ func (d *FsProductModel3dModel) Get3dModelsByParam(ctx context.Context, req Get3
return resp, err return resp, err
} }
func (d *FsProductModel3dModel) Update(ctx context.Context, id int64, data *FsProductModel3d) error { func (d *FsProductModel3dModel) Update(ctx context.Context, id int64, data *FsProductModel3d) error {
return d.db.WithContext(ctx).Where("`id` = ? ", id).Updates(&data).Error return d.db.WithContext(ctx).Where("`id` = ? and `status` =? ", id, 1).Updates(&data).Error
} }
func (d *FsProductModel3dModel) GetAllBySizeIdsTag(ctx context.Context, sizeIds []int64, tag int64, fields ...string) (resp []FsProductModel3d, err error) { func (d *FsProductModel3dModel) GetAllBySizeIdsTag(ctx context.Context, sizeIds []int64, tag int64, fields ...string) (resp []FsProductModel3d, err error) {
if len(sizeIds) == 0 { if len(sizeIds) == 0 {
return return
} }
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`size_id` in (?) and `tag` = ?", sizeIds, tag) db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`size_id` in (?) and `tag` = ? and `status` = ?", sizeIds, tag, 1)
if len(fields) != 0 { if len(fields) != 0 {
db = db.Select(fields[0]) db = db.Select(fields[0])
} }
@ -83,7 +94,7 @@ func (d *FsProductModel3dModel) GetAllBySizeIdsTag(ctx context.Context, sizeIds
return resp, err return resp, err
} }
func (d *FsProductModel3dModel) GetAll(ctx context.Context) (resp []FsProductModel3d, err error) { func (d *FsProductModel3dModel) GetAll(ctx context.Context) (resp []FsProductModel3d, err error) {
err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Find(&resp).Error err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`status` = ?", 1).Find(&resp).Error
return resp, err return resp, err
} }
@ -96,7 +107,7 @@ func (d *FsProductModel3dModel) GetGroupPartListByProductIds(ctx context.Context
if len(productIds) == 0 { if len(productIds) == 0 {
return return
} }
err = d.db.WithContext(ctx).Model(&FsProductModel3d{}). err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`product_id` in(?) and `status` =? ", productIds, 1).
Select("product_id,group_concat(part_list) as part_list"). Select("product_id,group_concat(part_list) as part_list").
Group("product_id").Find(&resp).Error Group("product_id").Find(&resp).Error
return resp, err return resp, err
@ -120,3 +131,24 @@ func (d *FsProductModel3dModel) GetOneBySizeIdTag(ctx context.Context, sizeId in
err = db.Take(&resp).Error err = db.Take(&resp).Error
return resp, err return resp, err
} }
func (d *FsProductModel3dModel) GetAllByProductIdTag(ctx context.Context, productId int64, tag int64, fields ...string) (resp []FsProductModel3d, err error) {
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
Where("`product_id` = ? and `tag` = ? and `status` = ?", productId, tag, 1).
Order("sort DESC")
if len(fields) != 0 {
db = db.Select(fields[0])
}
err = db.Find(&resp).Error
return resp, err
}
func (d *FsProductModel3dModel) FindOneByProductIdSizeIdTag(ctx context.Context, productId, sizeId, tag int64, fields ...string) (resp *FsProductModel3d, err error) {
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
Where("`product_id` = ? and `size_id` = ? and `tag` = ? and `status` = ?", productId, sizeId, tag, 1).
Order("sort DESC")
if len(fields) != 0 {
db = db.Select(fields[0])
}
err = db.Take(&resp).Error
return resp, err
}

View File

@ -2,6 +2,7 @@ package gmodel
import ( import (
"context" "context"
"time"
) )
func (m *FsShoppingCartModel) TableName() string { func (m *FsShoppingCartModel) TableName() string {
@ -12,10 +13,26 @@ func (m *FsShoppingCartModel) TableName() string {
type RelaFsShoppingCart struct { type RelaFsShoppingCart struct {
FsShoppingCart FsShoppingCart
ShoppingCartProduct *RelaFsProduct `json:"shopping_cart_product" gorm:"foreignkey:product_id;references:id"` ShoppingCartProduct *RelaFsProduct `json:"shopping_cart_product" gorm:"foreignkey:product_id;references:id"`
ShoppingCartProductPriceList []*FsProductPrice `json:"shopping_cart_product_price_list" gorm:"foreignkey:product_id;references:product_id"` ShoppingCartProductModel3d *FsProductModel3d `json:"shopping_cart_product_model3d_list" gorm:"foreignkey:model_id;references:id"`
ShoppingCartProductModel3dList []*FsProductModel3d `json:"shopping_cart_product_model3d_list" gorm:"foreignkey:product_id;references:product_id"`
ShoppingCartProductModel3dFitting *FsProductModel3d `json:"shopping_cart_product_model3d_list_fitting" gorm:"foreignkey:fitting_id;references:id"` ShoppingCartProductModel3dFitting *FsProductModel3d `json:"shopping_cart_product_model3d_list_fitting" gorm:"foreignkey:fitting_id;references:id"`
} }
type FsShoppingCartData struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id
UserId *int64 `gorm:"default:0;" json:"user_id"` // 用户id
ProductId *int64 `gorm:"default:0;" json:"product_id"` // 产品id
TemplateId *int64 `gorm:"default:0;" json:"template_id"` // 模板id
ModelId *int64 `gorm:"default:0;" json:"model_id"` // 模型id
SizeId *int64 `gorm:"default:0;" json:"size_id"` // 尺寸id
LightId *int64 `gorm:"default:0;" json:"light_id"` // 灯光id
FittingId *int64 `gorm:"default:0;" json:"fitting_id"` // 配件id
PurchaseQuantity *int64 `gorm:"default:0;" json:"purchase_quantity"` // 购买数量
Snapshot *map[string]interface{} `gorm:"default:'';" json:"snapshot"` //
SnapshotData *string `gorm:"default:'';" json:"snapshot_data"` //
IsSelected *int64 `gorm:"default:0;" json:"is_selected"` // 是否被选中 0非 1是
IsHighlyCustomized *int64 `gorm:"default:0;" json:"is_highly_customized"` // 是否高度定制 0非 1是针对客人高度定制只能后台增加如购物车
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
}
// 快照json数据结构 // 快照json数据结构
// 购物车快照数据结构 // 购物车快照数据结构

View File

@ -2,6 +2,7 @@ package gmodel
import ( import (
"gorm.io/gorm" "gorm.io/gorm"
"time"
) )
// fs_user 用户表 // fs_user 用户表
@ -13,7 +14,7 @@ type FsUser struct {
LastName *string `gorm:"default:'';" json:"last_name"` // LastName LastName *string `gorm:"default:'';" json:"last_name"` // LastName
Username *string `gorm:"index;default:'';" json:"username"` // Username *string `gorm:"index;default:'';" json:"username"` //
Company *string `gorm:"default:'';" json:"company"` // 公司名称 Company *string `gorm:"default:'';" json:"company"` // 公司名称
Mobile *string `gorm:"default:'';" json:"mobile"` // 手机号码 Mobile *string `gorm:"default:'';" json:"mobile"` //
PasswordHash *string `gorm:"default:'';" json:"password_hash"` // PasswordHash *string `gorm:"default:'';" json:"password_hash"` //
VerificationToken *string `gorm:"default:'';" json:"verification_token"` // VerificationToken *string `gorm:"default:'';" json:"verification_token"` //
PasswordResetToken *string `gorm:"default:'';" json:"password_reset_token"` // PasswordResetToken *string `gorm:"default:'';" json:"password_reset_token"` //
@ -21,16 +22,8 @@ type FsUser struct {
Type *int64 `gorm:"default:0;" json:"type"` // 1普通餐厅 2连锁餐厅 Type *int64 `gorm:"default:0;" json:"type"` // 1普通餐厅 2连锁餐厅
Status *int64 `gorm:"default:1;" json:"status"` // 1正常 0不正常 Status *int64 `gorm:"default:1;" json:"status"` // 1正常 0不正常
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除 1删除 IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除 1删除
CreatedAt *int64 `gorm:"default:0;" json:"created_at"` // 添加时间 Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
UpdatedAt *int64 `gorm:"default:0;" json:"updated_at"` // 更新时间 Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
IsOrderStatusEmail *int64 `gorm:"default:0;" json:"is_order_status_email"` // 订单状态改变时是否接收邮件
IsEmailAdvertisement *int64 `gorm:"default:0;" json:"is_email_advertisement"` // 是否接收邮件广告
IsOrderStatusPhone *int64 `gorm:"default:0;" json:"is_order_status_phone"` // 订单状态改变是是否接收电话
IsPhoneAdvertisement *int64 `gorm:"default:0;" json:"is_phone_advertisement"` // 是否接收短信广告
IsOpenRender *int64 `gorm:"default:0;" json:"is_open_render"` // 是否打开个性化渲染1开启0关闭
IsThousandFace *int64 `gorm:"default:0;" json:"is_thousand_face"` // 是否已经存在千人千面1存在0不存在
IsLowRendering *int64 `gorm:"default:0;" json:"is_low_rendering"` //
IsRemoveBg *int64 `gorm:"default:1;" json:"is_remove_bg"` // 用户上传logo是否去除背景
} }
type FsUserModel struct { type FsUserModel struct {
db *gorm.DB db *gorm.DB

View File

@ -4,6 +4,9 @@ package gmodel
import ( import (
"context" "context"
"encoding/json"
"fmt"
"fusenapi/utils/fssql"
"fusenapi/utils/handlers" "fusenapi/utils/handlers"
"gorm.io/gorm" "gorm.io/gorm"
@ -42,3 +45,39 @@ func (p *FsUserInfoModel) CreateOrUpdate(gormDB *gorm.DB, req *FsUserInfo) (resp
} }
return req, err return req, err
} }
func (m *FsUserInfoModel) MergeMetadata(userId int64, meta any) error {
return fssql.MetadataModulePATCH(m.db, "profile", FsUserInfo{}, map[string]any{
"base": meta,
}, "user_id = ?", userId)
}
func (m *FsUserInfoModel) GetProfile(ctx context.Context, pkey string, userId int64) (map[string]any, error) {
var baseinfo map[string]any
tname := fssql.GetGormTableName(m.db, FsUserInfo{})
if pkey == "." {
pkey = ""
} else {
pkey = "." + pkey
}
rawsql := fmt.Sprintf("select JSON_EXTRACT(metadata,'$%s') as query from %s where user_id = ? and module = 'profile' order by ctime DESC limit 1", pkey, tname)
err := m.db.Raw(rawsql, userId).Take(&baseinfo).Error
if err != nil {
return nil, err
}
v, ok := baseinfo["query"].(string)
if !ok {
return nil, nil
}
var info map[string]any
err = json.Unmarshal([]byte(v), &info)
if err != nil {
return nil, err
}
return info, nil
}

View File

@ -4,14 +4,11 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/fssql" "fusenapi/utils/fssql"
"time" "time"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -66,28 +63,26 @@ func InheritGuestIdResource(tx *gorm.DB, userId, guestId int64, afterDo func(txR
if guestId != 0 { if guestId != 0 {
// 继承guest_id的资源表 // 继承guest_id的资源表
err = txRes. err = txRes.
Where("guest_id = ?", guestId). Where("guest_id = ? and source != 'temp' and version != '0.0.0'", guestId).
UpdateColumn("user_id", userId).Error UpdateColumn("user_id", userId).Error
if err != nil && err != gorm.ErrRecordNotFound { if err != nil && err != gorm.ErrRecordNotFound {
logx.Info(err, "找到user_id1 afterDo")
return err return err
} }
err = txUserMaterial. err = txUserMaterial.
Where("guest_id = ?", guestId). Where("guest_id = ? and module != 'clear' and module != 'temp'", guestId).
UpdateColumn("user_id", userId).Error UpdateColumn("user_id", userId).Error
if err != nil && err != gorm.ErrRecordNotFound { if err != nil && err != gorm.ErrRecordNotFound {
logx.Info(err, "找到user_id1 afterDo")
return err return err
} }
err = txUserInfo. err = txUserInfo.
Where("guest_id = ?", guestId). Where("guest_id = ? and module != 'clear' and module != 'temp'", guestId).
UpdateColumn("user_id", userId).Error UpdateColumn("user_id", userId).Error
if err != nil && err != gorm.ErrRecordNotFound { if err != nil && err != gorm.ErrRecordNotFound {
logx.Info(err, "找到user_id1 afterDo")
return err return err
} }
} }
@ -120,9 +115,9 @@ func (u *FsUserModel) RegisterByGoogleOAuth(ctx context.Context, token *auth.Reg
if err != nil { if err != nil {
// 没有找到在数据库就创建注册 // 没有找到在数据库就创建注册
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {
createAt := time.Now().UTC().Unix() createAt := time.Now().UTC()
user.Email = &token.Email user.Email = &token.Email
user.CreatedAt = &createAt user.Ctime = &createAt
user.GoogleId = &googleId user.GoogleId = &googleId
user.PasswordHash = &token.Password user.PasswordHash = &token.Password
user.FirstName = &firstName user.FirstName = &firstName
@ -150,21 +145,6 @@ func (u *FsUserModel) RegisterByGoogleOAuth(ctx context.Context, token *auth.Reg
return user, nil return user, nil
} }
// SubscriptionStatus 订阅状态
type SubscriptionStatus struct {
SubEmail bool `json:"all_emails"`
ItemMap *struct {
} `json:"item_map"`
}
// UserProfile 个人信息
type UserProfile struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Resetaurant string `json:"resetaurant"`
SubStatus SubscriptionStatus `json:"sub_status"`
}
// 自平台的注册流程 // 自平台的注册流程
func (u *FsUserModel) RegisterByFusen(ctx context.Context, token *auth.RegisterToken) (user *FsUser, err error) { func (u *FsUserModel) RegisterByFusen(ctx context.Context, token *auth.RegisterToken) (user *FsUser, err error) {
@ -174,44 +154,41 @@ func (u *FsUserModel) RegisterByFusen(ctx context.Context, token *auth.RegisterT
var err error var err error
err = tx.Model(&FsUser{}).Where("email = ?", token.Email).Take(user).Error err = tx.Model(&FsUser{}).Where("email = ?", token.Email).Take(user).Error
log.Println("success", token.TraceId)
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {
FirstName := token.Extend["first_name"].(string) FirstName := token.Extend["first_name"].(string)
LastName := token.Extend["last_name"].(string) LastName := token.Extend["last_name"].(string)
Resetaurant := token.Extend["resetaurant"].(string) Resetaurant := token.Extend["resetaurant"].(string)
createAt := time.Now().UTC().Unix() createAt := time.Now().UTC()
user.Email = &token.Email user.Email = &token.Email
user.CreatedAt = &createAt user.Ctime = &createAt
user.PasswordHash = &token.Password user.PasswordHash = &token.Password
user.FirstName = &FirstName user.FirstName = &FirstName
user.LastName = &LastName user.LastName = &LastName
err = tx.Model(&FsUser{}).Create(user).Error err = tx.Model(&FsUser{}).Create(user).Error
if err != nil && err != gorm.ErrRecordNotFound { if err != nil && err != gorm.ErrRecordNotFound {
logx.Error(err)
return err return err
} }
log.Println("success", token.TraceId)
// 继承guest_id的资源表 // 继承guest_id的资源表
err = InheritGuestIdResource(tx, user.Id, token.GuestId, func(txResouce, txUserMaterial, txUserInfo *gorm.DB) error { err = InheritGuestIdResource(tx, user.Id, token.GuestId, func(txResouce, txUserMaterial, txUserInfo *gorm.DB) error {
log.Println("success", token.TraceId) userProfileBase := UserProfileBase{
userProfile := &UserProfile{
FirstName: FirstName, FirstName: FirstName,
LastName: LastName, LastName: LastName,
Resetaurant: Resetaurant, Resetaurant: Resetaurant,
} }
userProfile := &UserProfile{
ProfileBase: userProfileBase,
}
metadata, err := json.Marshal(userProfile) metadata, err := json.Marshal(userProfile)
if err != nil { if err != nil {
return err return err
} }
// txUserInfo.Where("user_id = ?", user.Id).Row().Err()
now := time.Now().UTC() now := time.Now().UTC()
uinfo := &FsUserInfo{ uinfo := &FsUserInfo{
Module: FsString("profile"), Module: FsString("profile"),
@ -222,18 +199,18 @@ func (u *FsUserModel) RegisterByFusen(ctx context.Context, token *auth.RegisterT
Utime: &now, Utime: &now,
} }
err = txUserInfo.Where("module = 'profile' and user_id = ?", uinfo.UserId).Take(nil).Error // logx.Error(metadata)
// txUserInfo.Statement.Table
log.Println(err, "找到user_id1") err = txUserInfo.Where("module = 'profile' and user_id = ?", *uinfo.UserId).Take(nil).Error
if err != nil { if err != nil {
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {
err = txUserInfo.Create(uinfo).Error err = tx.Model(&FsUserInfo{}).Create(uinfo).Error
// logx.Info(err, "*uinfo.UserId:", *uinfo.UserId, " ", uinfo.Id)
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {
return nil return nil
} }
} }
} else { } else {
log.Println("找到user_id2")
err = fssql.MetadataModulePATCH(txUserInfo, "profile", FsUserInfo{}, metadata, "user_id = ?", *uinfo.UserId) err = fssql.MetadataModulePATCH(txUserInfo, "profile", FsUserInfo{}, metadata, "user_id = ?", *uinfo.UserId)
if err != nil { if err != nil {
return err return err

View File

@ -35,3 +35,25 @@ func FsFloat(v float64) *float64 {
func FsBool(v bool) *bool { func FsBool(v bool) *bool {
return &v return &v
} }
// SubscriptionStatus 订阅状态
type SubscriptionStatus struct {
SubEmail bool `json:"all_emails"`
ItemMap *struct {
} `json:"item_map"`
}
type UserProfile struct {
ProfileBase UserProfileBase `json:"base"`
SubStatus SubscriptionStatus `json:"sub_status"`
}
// UserProfileBase 个人信息
type UserProfileBase struct {
FirstName string `json:"first_name"` // 首名
LastName string `json:"last_name"` // 后名
UserName string `json:"user_name"` // 用户名
Mobile string `json:"mobile"` // 电话
Resetaurant string `json:"resetaurant"` // 不知道干什么
Company string `json:"company"` // 公司
}

View File

@ -18,7 +18,6 @@ import (
"time" "time"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/zeromicro/go-zero/core/logx"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
_ "fusenapi/utils/auth" _ "fusenapi/utils/auth"
@ -97,14 +96,16 @@ func main() {
indexHtmlPath := vueBuild + "/index.html" indexHtmlPath := vueBuild + "/index.html"
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/") { if strings.HasPrefix(r.URL.Path, "/api/") {
err := r.ParseMultipartForm(100 << 20)
if err != nil { r.ParseMultipartForm(100 << 20)
logx.Error(err) // if err != nil {
} // logx.Error(err)
// }
// 对/api开头的请求进行反向代理 // 对/api开头的请求进行反向代理
proxy := httputil.NewSingleHostReverseProxy(apiURL) proxy := httputil.NewSingleHostReverseProxy(apiURL)
proxy.ServeHTTP(w, r) proxy.ServeHTTP(w, r)
return return
} else { } else {
@ -208,22 +209,22 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
target := url.URL{Scheme: "ws", Host: strings.Split(backend.HttpAddress, "//")[1], Path: r.URL.Path} target := url.URL{Scheme: "ws", Host: strings.Split(backend.HttpAddress, "//")[1], Path: r.URL.Path}
var transfer = func(src, dest *websocket.Conn) { var transfer = func(src, dest *websocket.Conn) {
defer src.Close()
defer dest.Close()
// TODO: 可以做错误处理
for { for {
mType, msg, err := src.ReadMessage() mType, msg, err := src.ReadMessage()
if err != nil { if err != nil {
log.Println(err) log.Println(err)
break return
} }
err = dest.WriteMessage(mType, msg) err = dest.WriteMessage(mType, msg)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
break return
} }
} }
src.Close()
dest.Close()
} }
header := r.Header.Clone() header := r.Header.Clone()
@ -247,6 +248,7 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
} }
conn, err := upgrader.Upgrade(w, r, nil) conn, err := upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
// defer conn.Close() // defer conn.Close()
@ -259,14 +261,14 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
// 解析目标URL包含了查询参数 // 解析目标URL包含了查询参数
targetURL, err := url.Parse(httpAddress + r.URL.String()) targetURL, err := url.Parse(httpAddress + r.URL.String())
if err != nil { if err != nil {
http.Error(w, "Error parsing target URL", http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
// 创建新的请求 // 创建新的请求
proxyReq, err := http.NewRequest(r.Method, targetURL.String(), r.Body) proxyReq, err := http.NewRequest(r.Method, targetURL.String(), r.Body)
if err != nil { if err != nil {
http.Error(w, "Error creating proxy request", http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@ -284,7 +286,7 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
// 发送请求 // 发送请求
resp, err := backend.Client.Do(proxyReq) resp, err := backend.Client.Do(proxyReq)
if err != nil { if err != nil {
http.Error(w, "Error sending proxy request", http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
@ -300,7 +302,7 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
w.WriteHeader(resp.StatusCode) w.WriteHeader(resp.StatusCode)
_, err = io.Copy(w, resp.Body) _, err = io.Copy(w, resp.Body)
if err != nil { if err != nil {
http.Error(w, "Error copying proxy response", http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
} }

View File

@ -4,64 +4,94 @@ single_server_name=$1
go mod tidy go mod tidy
go mod vendor go mod vendor
find /tmp/go-build* -mmin +5 -exec rm -rf {} +
find /tmp/go-link* -mmin +5 -exec rm -rf {} +
run_proxyserver() {
# 定义目录和screen名称
dir_path="./proxyserver"
screen_name="proxyserver"
# 进入目录
cd $dir_path
# 检查是否存在screen session
if screen -list | grep -q "$screen_name"; then
# 结束存在的screen session
screen -S $screen_name -X quit
fi
go build
# 启动新的screen session并运行go程序
echo "run $screen_name"
screen -dmS $screen_name -L ./$screen_name
}
# 定义一个函数来在每个服务器目录下运行 go run <server_name>.go # 定义一个函数来在每个服务器目录下运行 go run <server_name>.go
run_server() { run_server() {
server_name=$1 server_name=$1
echo "Running $server_name"
# 导航到相应的目录
cd server/$server_name
echo "build $server_name"
go build
# 如果之前存在相同名字的 screen 会话,先将其终止 # 如果之前存在相同名字的 screen 会话,先将其终止
# 首先尝试关闭已存在的screen会话
existing_session=$(screen -ls | grep -w "$server_name") existing_session=$(screen -ls | grep -w "$server_name")
if [ -n "$existing_session" ]; then if [ -n "$existing_session" ]; then
echo "Terminating existing screen session for $server_name" echo "Terminating existing screen session for $server_name"
screen -S "$server_name" -X quit screen -S "$server_name" -X quit
while [[ $(screen -ls | grep "\.$server_name\s") ]]; do
sleep 0.1s # 等待0.1秒后再次检查
echo "wait for $server_name"
done
fi fi
# 导航到相应的目录
cd server/$server_name # 循环检查screen进程是否存在
go build
[ -f .gitignore ] || echo $server_name > .gitignore [ -f .gitignore ] || echo $server_name > .gitignore
# 使用 screen 运行 go run <server_name>.go # 使用 screen 运行 go run <server_name>.go
echo "Running $server_name"
screen -dmS $server_name -L ./$server_name screen -dmS $server_name -L ./$server_name
# 返回到上一级目录 # 返回到上一级目录
cd - > /dev/null cd - > /dev/null
} }
find /tmp/go-build* -mmin +5 -exec rm -rf {} + if [ "$single_server_name" = "proxyserver" ]; then
find /tmp/go-link* -mmin +5 -exec rm -rf {} + # 重启proxyserver的逻辑
run_proxyserver
server_dirs=() # 初始化一个空数组
if [ -n "$single_server_name" ]; then
server_dirs=("$single_server_name")
else else
server_dirs=() # 初始化一个空数组
if [ -n "$single_server_name" ]; then
server_dirs=("$single_server_name")
else
for dir in server/*/ ; do # 遍历 "server/" 下的所有子目录 for dir in server/*/ ; do # 遍历 "server/" 下的所有子目录
dir=${dir%*/} # 删除末尾的 "/" dir=${dir%*/} # 删除末尾的 "/"
dir=${dir##*/} # 删除开头的 "server/" dir=${dir##*/} # 删除开头的 "server/"
server_dirs+=("$dir") # 添加到数组 server_dirs+=("$dir") # 添加到数组
done done
fi fi
# 在每个服务器目录下运行相应的 go 程序 # 在每个服务器目录下运行相应的 go 程序
for server_dir in "${server_dirs[@]}"; do for server_dir in "${server_dirs[@]}"; do
run_server $server_dir run_server $server_dir
done done
if [ -n "$single_server_name" ]; then
# 定义目录和screen名称 echo "no proxyserver restart"
dir_path="./proxyserver" else
screen_name="proxyserver" run_proxyserver
fi
# 进入目录
cd $dir_path
# 检查是否存在screen session
if screen -list | grep -q "$screen_name"; then
# 结束存在的screen session
screen -S $screen_name -X quit
fi fi
go build
# 启动新的screen session并运行go程序
screen -dmS $screen_name -L ./$screen_name

View File

@ -97,7 +97,7 @@ func CommonNotify(WebsocketAddr, wid string, event *wevent.WebsocketEvent) error
func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEmailConfirmation, userinfo *auth.UserInfo) (resp *basic.Response) { func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEmailConfirmation, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
logx.Error("找到user_id1 UserEmailConfirmation")
switch auth.OperateType(req.OpType) { switch auth.OperateType(req.OpType) {
case auth.OpTypeRegister: case auth.OpTypeRegister:

View File

@ -49,7 +49,7 @@ func (l *UserAddAddressLogic) UserAddAddress(req *types.RequestAddAddress, useri
isDefautl int64 = 1 // 默认地址为1 isDefautl int64 = 1 // 默认地址为1
) )
createOne := &gmodel.FsAddress{ // 构建FsAddress结构体 createOne := &gmodel.FsAddress{ // 构建FsAddress结构体
Name: &req.Name, AddressName: &req.Name,
FirstName: &req.FirstName, FirstName: &req.FirstName,
LastName: &req.LastName, LastName: &req.LastName,
Mobile: &req.Mobile, Mobile: &req.Mobile,
@ -68,12 +68,12 @@ func (l *UserAddAddressLogic) UserAddAddress(req *types.RequestAddAddress, useri
logx.Error(err) // 日志记录错误 logx.Error(err) // 日志记录错误
return resp.SetStatus(basic.CodeDbCreateErr) // 返回数据库创建错误 return resp.SetStatus(basic.CodeDbCreateErr) // 返回数据库创建错误
} }
return resp.SetStatus(basic.CodeOK, map[string]int64{"id": created.Id}) // 返回成功并返回地址ID return resp.SetStatus(basic.CodeOK, map[string]int64{"id": created.AddressId}) // 返回成功并返回地址ID
} }
address := &gmodel.FsAddress{ address := &gmodel.FsAddress{
Id: req.Id, AddressId: req.Id,
Name: &req.Name, AddressName: &req.Name,
FirstName: &req.FirstName, FirstName: &req.FirstName,
LastName: &req.LastName, LastName: &req.LastName,
Mobile: &req.Mobile, Mobile: &req.Mobile,
@ -88,11 +88,11 @@ func (l *UserAddAddressLogic) UserAddAddress(req *types.RequestAddAddress, useri
} }
// 插入数据库 更新地址 // 插入数据库 更新地址
err := m.UpdateAddAddress(l.ctx, address) err := m.UpdateAddress(l.ctx, address)
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
return resp.SetStatus(basic.CodeDbUpdateErr) return resp.SetStatus(basic.CodeDbUpdateErr)
} }
return resp.SetStatus(basic.CodeOK, map[string]int64{"id": address.Id}) return resp.SetStatus(basic.CodeOK, map[string]int64{"id": address.AddressId})
} }

View File

@ -7,6 +7,7 @@ import (
"fusenapi/server/home-user-auth/internal/types" "fusenapi/server/home-user-auth/internal/types"
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
@ -46,12 +47,12 @@ func (l *UserBasicInfoLogic) UserBasicInfo(req *types.Request, userinfo *auth.Us
return resp.SetStatus(basic.CodeOK, types.DataUserBasicInfo{ return resp.SetStatus(basic.CodeOK, types.DataUserBasicInfo{
Type: *user.Type, Type: *user.Type,
IsOrderStatusEmail: *user.IsOrderStatusEmail, // IsOrderStatusEmail: *user.IsOrderStatusEmail,
IsEmailAdvertisement: *user.IsEmailAdvertisement, // IsEmailAdvertisement: *user.IsEmailAdvertisement,
IsOrderStatusPhone: *user.IsOrderStatusPhone, // IsOrderStatusPhone: *user.IsOrderStatusPhone,
IsPhoneAdvertisement: *user.IsPhoneAdvertisement, // IsPhoneAdvertisement: *user.IsPhoneAdvertisement,
IsOpenRender: *user.IsOpenRender, // IsOpenRender: *user.IsOpenRender,
IsLowRendering: *user.IsLowRendering, // IsLowRendering: *user.IsLowRendering,
IsRemoveBg: *user.IsRemoveBg, // IsRemoveBg: *user.IsRemoveBg,
}) })
} }

View File

@ -45,8 +45,31 @@ func (l *UserLogoSetLogic) UserLogoSet(req *types.UserLogoSetReq, userinfo *auth
// 如果是,返回未授权的错误码 // 如果是,返回未授权的错误码
return resp.SetStatus(basic.CodeUnAuth) return resp.SetStatus(basic.CodeUnAuth)
} }
var nowTime = time.Now().UTC()
if req.LogoSelectedId == 0 { if req.LogoSelectedId == 0 {
return resp.SetStatus(basic.CodeLogoSetCategory, "logo logo_selected_id not null") NewFsUserMaterialModel1 := gmodel.NewFsUserMaterialModel(l.svcCtx.MysqlConn)
NewFsUserMaterialModelRow1 := NewFsUserMaterialModel1.RowSelectBuilder(nil).Where("id = ?", 0)
defaultMaterialInfo, err := NewFsUserMaterialModel1.FindOne(l.ctx, NewFsUserMaterialModelRow1.Model(&gmodel.FsUserMaterial{}))
if err != nil {
logc.Errorf(l.ctx, "defaultMaterialInfo FindOne err%+v", err)
return resp.SetStatus(basic.CodeLogoSetCategory, "logo not find")
}
var defaultMaterial = gmodel.FsUserMaterial{
Module: defaultMaterialInfo.Module,
UserId: &userinfo.UserId,
GuestId: &userinfo.GuestId,
ResourceId: defaultMaterialInfo.ResourceId,
ResourceUrl: defaultMaterialInfo.ResourceUrl,
Ctime: &nowTime,
}
MaterialCreateRes := l.svcCtx.MysqlConn.Create(&defaultMaterial)
err = MaterialCreateRes.Error
if err != nil {
logc.Errorf(l.ctx, "defaultMaterialInfo Create err%+v", err)
return resp.SetStatus(basic.CodeLogoSetCategory, "logo not find")
}
req.LogoSelectedId = defaultMaterial.Id
} }
if req.SetLogoCategory == 1 && req.CategoryId == 0 { if req.SetLogoCategory == 1 && req.CategoryId == 0 {
return resp.SetStatus(basic.CodeLogoSetCategory, "logo category_id not null") return resp.SetStatus(basic.CodeLogoSetCategory, "logo category_id not null")
@ -73,7 +96,6 @@ func (l *UserLogoSetLogic) UserLogoSet(req *types.UserLogoSetReq, userinfo *auth
return resp.SetStatus(basic.CodeLogoSetCategory, "logo not find") return resp.SetStatus(basic.CodeLogoSetCategory, "logo not find")
} }
var nowTime = time.Now().UTC()
err = l.svcCtx.MysqlConn.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error { err = l.svcCtx.MysqlConn.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error {
var metadataMapOldUserMaterial map[string]interface{} var metadataMapOldUserMaterial map[string]interface{}
if userMaterialInfo.Metadata != nil { if userMaterialInfo.Metadata != nil {

View File

@ -6,27 +6,27 @@ import (
"fusenapi/utils/basic" "fusenapi/utils/basic"
"fusenapi/server/pay/internal/logic" "fusenapi/server/info/internal/logic"
"fusenapi/server/pay/internal/svc" "fusenapi/server/info/internal/svc"
"fusenapi/server/pay/internal/types" "fusenapi/server/info/internal/types"
) )
func OrderPaymentIntentHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { func AddressAddHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.OrderPaymentIntentReq var req types.AddressRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req) userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil { if err != nil {
return return
} }
// 创建一个业务逻辑层实例 // 创建一个业务逻辑层实例
l := logic.NewOrderPaymentIntentLogic(r.Context(), svcCtx) l := logic.NewAddressAddLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l) rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl) basic.BeforeLogic(w, r, rl)
resp := l.OrderPaymentIntent(&req, userinfo) resp := l.AddressAdd(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) { if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp) basic.NormalAfterLogic(w, r, resp)

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func AddressDefaultHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AddressIdRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressDefaultLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressDefault(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func AddressDeleteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AddressIdRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressDeleteLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressDelete(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func AddressListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.Request
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressListLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressList(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func AddressUpdateHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AddressRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressUpdateLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressUpdate(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -17,6 +17,41 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/info/user", Path: "/api/info/user",
Handler: InfoHandler(serverCtx), Handler: InfoHandler(serverCtx),
}, },
{
Method: http.MethodPost,
Path: "/api/info/user/profile",
Handler: UserGetProfileHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/user/profile/base/update",
Handler: UpdateProfileBaseHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/address/default",
Handler: AddressDefaultHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/address/add",
Handler: AddressAddHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/address/update",
Handler: AddressUpdateHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/address/delete",
Handler: AddressDeleteHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/api/info/address/list",
Handler: AddressListHandler(serverCtx),
},
}, },
) )
} }

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func UpdateProfileBaseHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ProfileBaseRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewUpdateProfileBaseLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.UpdateProfileBase(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func UserGetProfileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.QueryProfileRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewUserGetProfileLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.UserGetProfile(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,93 @@
package logic
import (
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressAddLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressAddLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressAddLogic {
return &AddressAddLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressAddLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressAddLogic) AddressAdd(req *types.AddressRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
// 确认这个IsDefault的值范围
if !auth.CheckValueRange(req.IsDefault, 0, 1) {
return resp.SetStatus(basic.CodeSafeValueRangeErr) // IsDefault值超出范围, 返回安全值范围错误
}
m := l.svcCtx.AllModels.FsAddress // 创建地址模型
// 如果ID为0, 表示新增地址
var (
country string = "USA" // 国家默认为美国
isDefautl int64 = 1 // 默认地址为1
status int64 = 1 // 默认地址状态为1(正常)
)
createOne := &gmodel.FsAddress{ // 构建FsAddress结构体
AddressName: &req.AddressName,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Country: &country,
Status: &status,
UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &isDefautl,
}
_, err := m.CreateOne(l.ctx, createOne) // 新增地址
if err != nil {
logx.Error(err) // 日志记录错误
return resp.SetStatus(basic.CodeDbCreateErr) // 返回数据库创建错误
}
addresses, err := m.GetUserAllAddress(l.ctx, userinfo.UserId)
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeDbSqlErr) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK, map[string]any{
"address_list": addresses,
}) // 返回成功并返回地址ID
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressAddLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -0,0 +1,52 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressDefaultLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressDefaultLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressDefaultLogic {
return &AddressDefaultLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressDefaultLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressDefaultLogic) AddressDefault(req *types.AddressIdRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
err := l.svcCtx.AllModels.FsAddress.SettingUserDefaultAddress(l.ctx, userinfo.UserId, req.AddressId)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressDefaultLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -0,0 +1,52 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressDeleteLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressDeleteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressDeleteLogic {
return &AddressDeleteLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressDeleteLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressDeleteLogic) AddressDelete(req *types.AddressIdRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
err := l.svcCtx.AllModels.FsAddress.DeleteOne(l.ctx, req.AddressId, userinfo.UserId)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressDeleteLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -0,0 +1,56 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressListLogic {
return &AddressListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressListLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressListLogic) AddressList(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
m := l.svcCtx.AllModels.FsAddress // 创建地址模型
result, err := m.GetUserAllAddress(l.ctx, userinfo.UserId)
if err != nil {
logx.Error(err) // 日志记录错误
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, err.Error()) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK, map[string]any{
"address_list": result,
})
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressListLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -0,0 +1,76 @@
package logic
import (
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"time"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressUpdateLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressUpdateLogic {
return &AddressUpdateLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressUpdateLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressUpdateLogic) AddressUpdate(req *types.AddressRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
now := time.Now().UTC()
if req.AddressId == 0 {
return resp.SetStatusWithMessage(basic.CodeApiErr, "address_id must setting")
}
address := gmodel.FsAddress{
AddressId: req.AddressId,
UserId: &userinfo.UserId,
IsDefault: &req.IsDefault,
AddressName: &req.AddressName,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
ZipCode: &req.ZipCode,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Utime: &now,
}
err := l.svcCtx.AllModels.FsAddress.UpdateAddress(l.ctx, &address)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressUpdateLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -39,6 +39,7 @@ func NewInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InfoLogic {
var ModuleTable map[string]string = map[string]string{ var ModuleTable map[string]string = map[string]string{
"userinfo": "fs_user_info", "userinfo": "fs_user_info",
"material": "fs_user_material", "material": "fs_user_material",
"address": "fs_address", // TODO: 地址列表
} }
type ModuleQuery struct { type ModuleQuery struct {
@ -82,6 +83,38 @@ func (mquery *ModuleQuery) EncodeEmpty() map[string]any {
return qstr return qstr
} }
func QueryDefault(conn *gorm.DB, module string, moduleQuery string, tname string) map[string]any {
qname := strings.Split(moduleQuery, ".")
queryAsName := qname[len(qname)-1]
sqlstr := fmt.Sprintf(
"select JSON_EXTRACT(metadata,'$.%s') as %s from %s where module = '%s' and user_id = 0 and guest_id = 0 order by ctime DESC limit 1",
moduleQuery, // logo_selected
queryAsName, // logo_selected
tname, // fs_user_info
module, // profile
)
raw := conn.Raw(sqlstr)
var info map[string]any
err := raw.Scan(&info).Error
if err == gorm.ErrRecordNotFound {
logx.Error(err)
}
if v, ok := info[queryAsName]; ok {
var qinfo map[string]any
err := json.Unmarshal([]byte(v.(string)), &qinfo)
if err != nil {
logx.Error(err)
} else {
info[queryAsName] = qinfo
}
}
return info
}
func (l *InfoLogic) Info(req *types.UserInfoRequest, userinfo *auth.UserInfo) (resp *basic.Response) { func (l *InfoLogic) Info(req *types.UserInfoRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
@ -178,9 +211,70 @@ func (l *InfoLogic) Info(req *types.UserInfoRequest, userinfo *auth.UserInfo) (r
} }
} }
// 隐含白板用户逻辑
if v, ok := metadict["userinfo.profile"]; ok {
if v == nil {
info := QueryDefault(l.svcCtx.MysqlConn, "profile", "logo_selected", "fs_user_info")
metadict["userinfo.profile"] = info
} else {
profileDict := v.(map[string]any)
if _, ok := profileDict["logo_selected"]; !ok {
info := QueryDefault(l.svcCtx.MysqlConn, "profile", "logo_selected", "fs_user_info")
profileDict["logo_selected"] = info["logo_selected"]
}
}
} else if v, ok := metadict["userinfo.profile.logo_selected"]; ok {
if v == nil {
info := QueryDefault(l.svcCtx.MysqlConn, "profile", "logo_selected", "fs_user_info")
metadict["userinfo.profile.logo_selected"] = info
}
} else {
var info map[string]any
for k, v := range metadict {
if v == nil {
if strings.HasPrefix(k, "userinfo.profile.logo_selected") {
if info == nil {
info = QueryDefault(l.svcCtx.MysqlConn, "profile", "logo_selected", "fs_user_info")
}
curValue, err := GetMapValueByKey(info, strings.Split(k, ".")[2:])
if err != nil {
logx.Error(err, info)
continue
// return resp.SetStatus(basic.CodeOK, metadict)
}
metadict[k] = curValue
// curValue
}
}
}
}
return resp.SetStatus(basic.CodeOK, metadict) return resp.SetStatus(basic.CodeOK, metadict)
} }
func GetMapValueByKey(info map[string]interface{}, keys []string) (interface{}, error) {
// keys := strings.Split(key, ".")[2:]
for _, k := range keys {
if cur, ok := info[k]; ok {
if curMap, ok := cur.(map[string]interface{}); ok {
info = curMap
} else {
// logx.Error(cur)
return cur, nil
}
} else {
return nil, fmt.Errorf("info keys is not exists %#v", keys)
}
}
return info, nil
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 // 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *InfoLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { // func (l *InfoLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp) // // httpx.OkJsonCtx(r.Context(), w, resp)

View File

@ -6,6 +6,7 @@ import (
"fusenapi/initalize" "fusenapi/initalize"
"fusenapi/model/gmodel" "fusenapi/model/gmodel"
"fusenapi/utils/check" "fusenapi/utils/check"
"fusenapi/utils/fssql"
"log" "log"
"strings" "strings"
"testing" "testing"
@ -117,57 +118,47 @@ func TestMain(t *testing.T) {
if v == nil { if v == nil {
info := QueryDefault(conn, "profile", "logo_selected", "fs_user_info") info := QueryDefault(conn, "profile", "logo_selected", "fs_user_info")
log.Println(info)
metadict["userinfo.profile"] = info metadict["userinfo.profile"] = info
// log.Println(metadict)
} else { } else {
profileDict := v.(map[string]any) profileDict := v.(map[string]any)
if _, ok := profileDict["logo_selected"]; !ok { if _, ok := profileDict["logo_selected"]; !ok {
info := QueryDefault(conn, "profile", "logo_selected", "fs_user_info") info := QueryDefault(conn, "profile", "logo_selected", "fs_user_info")
profileDict["logo_selected"] = info["logo_selected"] profileDict["logo_selected"] = info["logo_selected"]
} }
} }
} else if v, ok := metadict["userinfo.profile.logo_selected"]; ok { } else if v, ok := metadict["userinfo.profile.logo_selected"]; ok {
if v == nil { if v == nil {
info := QueryDefault(conn, "profile", "logo_selected", "fs_user_info")
metadict["userinfo.profile.logo_selected"] = info
} }
} } else {
log.Println(metadict)
return
}
func QueryDefault(conn *gorm.DB, module string, moduleQuery string, tname string) map[string]any {
qname := strings.Split(moduleQuery, ".")
queryAsName := qname[len(qname)-1]
sqlstr := fmt.Sprintf(
"select JSON_EXTRACT(metadata,'$.%s') as %s from %s where module = '%s' and user_id = 0 and guest_id = 0 order by ctime DESC limit 1",
moduleQuery, // logo_selected
queryAsName, // logo_selected
tname, // fs_user_info
module, // profile
)
raw := conn.Raw(sqlstr)
var info map[string]any var info map[string]any
err := raw.Scan(&info).Error for k, v := range metadict {
if err == gorm.ErrRecordNotFound { if v == nil {
logx.Error(err) if strings.HasPrefix(k, "userinfo.profile.logo_selected") {
if info == nil {
info = QueryDefault(conn, "profile", "logo_selected", "fs_user_info")
} }
return info
curValue, err := GetMapValueByKey(info, strings.Split(k, ".")[2:])
if err != nil {
logx.Error(err, info)
continue
// return resp.SetStatus(basic.CodeOK, metadict)
}
metadict[k] = curValue
// curValue
}
}
}
}
} }
func TestCaseJSON_EXTRACT(t *testing.T) { func TestCaseJSON_EXTRACT(t *testing.T) {
userProfile := &gmodel.UserProfile{ userProfile := &gmodel.UserProfile{}
FirstName: "FirstName",
LastName: "LastName",
Resetaurant: "Resetaurant",
}
metadata, err := json.Marshal(userProfile) metadata, err := json.Marshal(userProfile)
if err != nil { if err != nil {
panic(err) panic(err)
@ -185,6 +176,14 @@ func TestCaseJSON_EXTRACT(t *testing.T) {
conn := initalize.InitMysql("fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen") conn := initalize.InitMysql("fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen")
// err = conn.Exec(updatesql, 6).Error // err = conn.Exec(updatesql, 6).Error
log.Println(conn.Model(&gmodel.FsChangeCode{}).Select("id").Where("id = 5").Take(nil).Error) info := gmodel.UserProfileBase{}
var baseinfo map[string]any
tname := fssql.GetGormTableName(conn, gmodel.FsUserInfo{})
rawsql := fmt.Sprintf("select JSON_EXTRACT(metadata,'$.base') as base from %s where user_id = ? and module = ? order by ctime DESC limit 1", tname)
tx := conn.Raw(rawsql, 162, "profile").Take(&baseinfo)
log.Println(tx.Error)
json.Unmarshal([]byte(baseinfo["base"].(string)), &info)
log.Println(err) log.Println(err)
} }

View File

@ -0,0 +1,52 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type UpdateProfileBaseLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUpdateProfileBaseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateProfileBaseLogic {
return &UpdateProfileBaseLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *UpdateProfileBaseLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *UpdateProfileBaseLogic) UpdateProfileBase(req *types.ProfileBaseRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
err := l.svcCtx.AllModels.FsUserInfo.MergeMetadata(userinfo.UserId, req)
if err != nil {
logx.Error(err) // 日志记录错误
return resp.SetStatus(basic.CodeDbSqlErr, err.Error()) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *UpdateProfileBaseLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -0,0 +1,52 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type UserGetProfileLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUserGetProfileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserGetProfileLogic {
return &UserGetProfileLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *UserGetProfileLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *UserGetProfileLogic) UserGetProfile(req *types.QueryProfileRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
profileBase, err := l.svcCtx.AllModels.FsUserInfo.GetProfile(l.ctx, req.TopKey, userinfo.UserId)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK, profileBase)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *UserGetProfileLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -9,6 +9,46 @@ type UserInfoRequest struct {
Module []string `json:"module"` Module []string `json:"module"`
} }
type AddressObjectRequest struct {
AddressId int64 `json:"address_id"` // 地址id
AddressName string `json:"address_name"` // 地址
}
type AddressIdRequest struct {
AddressId int64 `json:"address_id"` // 地址id
}
type AddressNameRequest struct {
AddressName string `json:"address_name"` // 地址
}
type AddressRequest struct {
AddressId int64 `json:"address_id,optional"`
IsDefault int64 `json:"is_default"` //是否默认
AddressName string `json:"address_name"` //收货人
FirstName string `json:"first_name"` //first_name
LastName string `json:"last_name"` //last_name
Mobile string `json:"mobile"` //手机
ZipCode string `json:"zip_code"` //邮编
Street string `json:"street"` //街道
Suite string `json:"suite"` //房号
City string `json:"city"` //城市
State string `json:"state"` //州
}
type ProfileBaseRequest struct {
FirstName *string `json:"first_name,optional,omitempty"` // 首名
LastName *string `json:"last_name,optional,omitempty"` // 后名
UserName *string `json:"user_name,optional,omitempty"` // 用户名
Mobile *string `json:"mobile,optional,omitempty"` // 电话
Resetaurant *string `json:"resetaurant,optional,omitempty"` // 不知道干什么
Company *string `json:"company,optional,omitempty"` // 公司
}
type QueryProfileRequest struct {
TopKey string `json:"top_key"` // 首名
}
type Request struct { type Request struct {
} }
@ -32,10 +72,10 @@ type File struct {
} }
type Meta struct { type Meta struct {
TotalCount int64 `json:"totalCount"` TotalCount int64 `json:"total_count"`
PageCount int64 `json:"pageCount"` PageCount int64 `json:"page_count"`
CurrentPage int `json:"currentPage"` CurrentPage int `json:"current_page"`
PerPage int `json:"perPage"` PerPage int `json:"per_page"`
} }
// Set 设置Response的Code和Message值 // Set 设置Response的Code和Message值

View File

@ -3,7 +3,7 @@ Host: 0.0.0.0
Port: 9907 Port: 9907
Timeout: 15000 #服务超时时间(毫秒) Timeout: 15000 #服务超时时间(毫秒)
SourceMysql: fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen SourceMysql: fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen
SourceRabbitMq: SourceRabbitMq: 213
Log: Log:
Stat: false Stat: false
Auth: Auth:

View File

@ -47,7 +47,7 @@ func (l *CreateOrderLogic) CreateOrder(req *types.CreateOrderReq, userinfo *auth
OriginalCurrency: string(constants.CURRENCYUSD), OriginalCurrency: string(constants.CURRENCYUSD),
UserId: userinfo.UserId, UserId: userinfo.UserId,
CartIds: req.CartIds, CartIds: req.CartIds,
DeliveryMethod: req.DeliveryMethod, DeliveryMethod: constants.DELIVERYMETHODDSCLOUDSTORE,
}) })
if err != nil { if err != nil {

View File

@ -1,6 +1,7 @@
package logic package logic
import ( import (
"fusenapi/service/repositories"
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
@ -38,7 +39,22 @@ func (l *CreatePrePaymentByBalanceLogic) CreatePrePaymentByBalance(req *types.Cr
return resp.SetStatus(basic.CodeUnAuth) return resp.SetStatus(basic.CodeUnAuth)
} }
return resp.SetStatus(basic.CodeOK) res, err := l.svcCtx.Repositories.NewOrder.CreatePrePaymentByBalance(l.ctx, &repositories.CreatePrePaymentByBalanceReq{
UserId: userinfo.UserId,
OrderSn: req.OrderSn,
Country: "US",
Currency: "usd",
StripeKey: l.svcCtx.Config.PayConfig.Stripe.Key,
})
if err != nil {
return resp.SetStatus(&res.ErrorCode)
}
return resp.SetStatus(basic.CodeOK, map[string]interface{}{
"order_detail": res.OrderDetail,
"order_pay": res.OrderPay,
})
} }
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 // 处理逻辑后 w,r 如:重定向, resp 必须重新处理

View File

@ -11,7 +11,6 @@ type OrderDetailReq struct {
type CreateOrderReq struct { type CreateOrderReq struct {
CartIds []int64 `json:"cart_ids"` CartIds []int64 `json:"cart_ids"`
DeliveryMethod int64 `json:"delivery_method,options=[1,2]"`
} }
type CreatePrePaymentByDepositReq struct { type CreatePrePaymentByDepositReq struct {

View File

@ -12,11 +12,6 @@ import (
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes( server.AddRoutes(
[]rest.Route{ []rest.Route{
{
Method: http.MethodPost,
Path: "/api/pay/payment-intent",
Handler: OrderPaymentIntentHandler(serverCtx),
},
{ {
Method: http.MethodPost, Method: http.MethodPost,
Path: "/api/pay/refund", Path: "/api/pay/refund",

View File

@ -1,181 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/pay/internal/svc"
"fusenapi/server/pay/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type OrderPaymentIntentLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewOrderPaymentIntentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OrderPaymentIntentLogic {
return &OrderPaymentIntentLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *OrderPaymentIntentLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *OrderPaymentIntentLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }
func (l *OrderPaymentIntentLogic) OrderPaymentIntent(req *types.OrderPaymentIntentReq, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
// if userinfo == nil || userinfo.UserId == 0 {
// return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order not found")
// }
// // 查询订单数据
// orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
// orderInfo, err := orderModel.FindOneBySn(l.ctx, userinfo.UserId, req.Sn)
// if err != nil {
// if errors.Is(err, gorm.ErrRecordNotFound) {
// return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order not found")
// }
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get order info")
// }
// // 校验订单状态
// if *orderInfo.IsCancel == 1 {
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "order cancelled")
// }
// // 校验地址信息
// addressModel := gmodel.NewFsAddressModel(l.svcCtx.MysqlConn)
// _, err = addressModel.GetOne(l.ctx, req.AddressId, userinfo.UserId)
// if err != nil {
// if errors.Is(err, gorm.ErrRecordNotFound) {
// return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "address not found")
// }
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get address info")
// }
// // 校验订单支付信息
// if *orderInfo.IsPayCompleted == 1 {
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "order is pay completed")
// }
// // 判断订单状态以及该支付金额
// var nowAt int64 = time.Now().UTC().Unix()
// var payAmount int64
// if *orderInfo.Status == int64(constants.STATUS_NEW_NOT_PAY) {
// payAmount = *orderInfo.TotalAmount / 2
// *orderInfo.DeliveryMethod = req.DeliveryMethod
// *orderInfo.AddressId = req.AddressId
// *orderInfo.PayMethod = req.PayMethod
// } else {
// payAmount = *orderInfo.TotalAmount - *orderInfo.TotalAmount/2
// }
// payConfig := &pay.Config{}
// var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
// OrderSn: req.Sn,
// ProductName: "支付标题",
// Amount: payAmount,
// Currency: "eur",
// Quantity: 1,
// ProductDescription: "支付描述",
// }
// var resData types.OrderPaymentIntentRes
// // 事务处理
// ctx := l.ctx
// err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error {
// // 支付记录--处理 //支付记录改为一条订单多条,分首款尾款
// var payStatus int64 = 0
// var orderSource int64 = 1
// var payStage int64
// var fspay *gmodel.FsPay
// newFsPayModel := gmodel.NewFsPayModel(connGorm)
// if *orderInfo.Status == int64(constants.STATUS_NEW_NOT_PAY) {
// fspay, err = newFsPayModel.RBGetListByOrderNumberStage(ctx, *orderInfo.Sn, 1)
// if err != nil {
// if !errors.Is(err, gorm.ErrRecordNotFound) {
// return err
// }
// }
// payStage = 1
// } else {
// fspay, err = newFsPayModel.RBGetListByOrderNumberStage(ctx, *orderInfo.Sn, 2)
// if err != nil {
// if !errors.Is(err, gorm.ErrRecordNotFound) {
// return err
// }
// }
// payStage = 2
// }
// // 支付预付--生成
// if constants.PayMethod(req.PayMethod) == constants.PAYMETHOD_STRIPE {
// payConfig.Stripe.Key = l.svcCtx.Config.PayConfig.Stripe.Key
// generatePrepaymentReq.SuccessURL = l.svcCtx.Config.PayConfig.Stripe.SuccessURL
// generatePrepaymentReq.CancelURL = l.svcCtx.Config.PayConfig.Stripe.CancelURL
// }
// payDriver := pay.NewPayDriver(req.PayMethod, payConfig)
// prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
// if err != nil {
// return err
// }
// // 订单信息--修改
// err = gmodel.NewFsOrderModel(connGorm).RBUpdate(ctx, orderInfo)
// if err != nil {
// return err
// }
// if fspay == nil {
// fspay = &gmodel.FsPay{
// UserId: orderInfo.UserId,
// OrderNumber: orderInfo.Sn,
// CreatedAt: &nowAt,
// }
// } else {
// fspay.UpdatedAt = &nowAt
// }
// fspay.PayAmount = &payAmount
// fspay.PayStage = &payStage
// //fspay.TradeNo = &prepaymentRes.TradeNo
// fspay.PaymentMethod = &req.PayMethod
// fspay.OrderSource = &orderSource
// fspay.PayStatus = &payStatus
// _, err = newFsPayModel.RBCreateOrUpdate(ctx, fspay)
// if err != nil {
// return err
// }
// resData.RedirectUrl = prepaymentRes.URL
// resData.ClientSecret = prepaymentRes.ClientSecret
// return nil
// })
// if err != nil {
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to make payment")
// }
return resp.SetStatusWithMessage(basic.CodeOK, "success")
}

View File

@ -1,16 +1,24 @@
package logic package logic
import ( import (
"encoding/json"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel" "fusenapi/model/gmodel"
"fusenapi/service/repositories"
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
"time"
"context" "context"
"fusenapi/server/pay/internal/svc" "fusenapi/server/pay/internal/svc"
"fusenapi/server/pay/internal/types" "fusenapi/server/pay/internal/types"
"github.com/stripe/stripe-go/v74" "github.com/stripe/stripe-go/v75"
"github.com/stripe/stripe-go/v75/webhook"
"github.com/zeromicro/go-zero/core/logc"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
@ -42,110 +50,116 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
// stripe.Key = l.svcCtx.Config.PayConfig.Stripe.Key stripe.Key = l.svcCtx.Config.PayConfig.Stripe.Key
// event := stripe.Event{} event := stripe.Event{}
// if err := json.Unmarshal(req.Payload, &event); err != nil { if err := json.Unmarshal(req.Payload, &event); err != nil {
// logx.Error(err) logc.Errorf(l.ctx, "StripeWebhookLogic StripeWebhook Unmarshal err:%v", err)
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail") return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail")
// } }
// fmt.Println(req)
// fmt.Println(event)
// endpointSecret := l.svcCtx.Config.PayConfig.Stripe.EndpointSecret endpointSecret := l.svcCtx.Config.PayConfig.Stripe.EndpointSecret
// signatureHeader := req.StripeSignature signatureHeader := req.StripeSignature
// event, err := webhook.ConstructEvent(req.Payload, signatureHeader, endpointSecret) fmt.Println(endpointSecret)
event, err := webhook.ConstructEvent(req.Payload, signatureHeader, endpointSecret)
if err != nil {
logc.Errorf(l.ctx, "webhook.ConstructEvent err:%v", err)
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "Webhook signature verification failed")
}
// 支付回调事件日志
var payMethod = int64(constants.PAYMETHOD_STRIPE)
var nowTime = time.Now().UTC()
var eventData = []byte(event.Data.Raw)
eventType := string(event.Type)
l.HandlePayEventCreate(&gmodel.FsOrderTradeEvent{
PayMethod: &payMethod,
EventId: &event.ID,
EventType: &eventType,
EventData: &eventData,
Ctime: &nowTime,
})
// Unmarshal the event data into an appropriate struct depending on its Type
fmt.Println("事件类型", event.Type)
switch event.Type {
case "charge.succeeded":
var charge stripe.Charge
err := json.Unmarshal(event.Data.Raw, &charge)
if err != nil {
logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type charge.succeeded")
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.succeeded")
}
err = l.HandleChargeSucceeded(&charge, event.ID)
if err != nil {
logx.Errorf("err%+vdesc%s", err, "pay notify handle payment_intent.succeeded")
return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded")
}
case "checkout.session.completed":
// checkout checkout.session.completed 处理逻辑
// var session stripe.CheckoutSession
// err := json.Unmarshal(event.Data.Raw, &session)
// if err != nil { // if err != nil {
// logx.Error(err) // logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "Webhook signature verification failed") // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// } // }
// fmt.Println("checkout.session.completed")
// // 新增支付回调事件日志 // err = l.handlePaymentSessionCompleted(session.ID, session.PaymentIntent.ID)
// var payMethod = int64(constants.PAYMETHOD_STRIPE) // if err != nil {
// var nowTime = time.Now().UTC().Unix() // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "checkout.session.completed fail")
// var eventData = string(event.Data.Raw)
// var fsPayEvent = &gmodel.FsPayEvent{
// PayMethod: &payMethod,
// EventId: &event.ID,
// EventType: &event.Type,
// EventData: &eventData,
// EventCreated: &event.Created,
// Ip: &req.RemoteAddr,
// CreatedAt: &nowTime,
// } // }
// l.HandlePayEventCreate(fsPayEvent) case "payment_intent.succeeded":
// // Unmarshal the event data into an appropriate struct depending on its Type
// switch event.Type {
// case "charge.succeeded":
// // var charge stripe.Charge
// // err := json.Unmarshal(event.Data.Raw, &charge)
// // if err != nil {
// // logx.Error(err)
// // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.succeeded")
// // }
// case "checkout.session.completed":
// // checkout checkout.session.completed 处理逻辑
// // var session stripe.CheckoutSession
// // err := json.Unmarshal(event.Data.Raw, &session)
// // if err != nil {
// // logx.Error(err)
// // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// // }
// // fmt.Println("checkout.session.completed")
// // err = l.handlePaymentSessionCompleted(session.ID, session.PaymentIntent.ID)
// // if err != nil {
// // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "checkout.session.completed fail")
// // }
// case "payment_intent.succeeded":
// var paymentIntent stripe.PaymentIntent // var paymentIntent stripe.PaymentIntent
// err := json.Unmarshal(event.Data.Raw, &paymentIntent) // err := json.Unmarshal(event.Data.Raw, &paymentIntent)
// if err != nil { // if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type payment_intent.succeeded") // logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded") // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// } // }
// err = l.HandlePaymentIntentSucceeded(&paymentIntent) // err = l.HandlePaymentIntentSucceeded(&paymentIntent, event.ID)
// if err != nil { // if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify handle payment_intent.succeeded") // logx.Errorf("err%+vdesc%s", err, "pay notify handle payment_intent.succeeded")
// return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded") // return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded")
// } // }
// case "payment_method.attached": case "payment_method.attached":
// var paymentMethod stripe.PaymentMethod // var paymentMethod stripe.PaymentMethod
// err := json.Unmarshal(event.Data.Raw, &paymentMethod) // err := json.Unmarshal(event.Data.Raw, &paymentMethod)
// if err != nil { // if err != nil {
// logx.Error(err) // logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_method.attached") // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_method.attached")
// } // }
// case "charge.refunded": case "charge.refunded":
// var chargeRefunded stripe.Charge var chargeRefunded stripe.Charge
// err := json.Unmarshal(event.Data.Raw, &chargeRefunded) err := json.Unmarshal(event.Data.Raw, &chargeRefunded)
// if err != nil { if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type charge.refunded") logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type charge.refunded")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.refunded") return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.refunded")
// } }
// err = l.HandleChargeRefunded(&chargeRefunded) err = l.HandleChargeRefunded(&chargeRefunded)
// if err != nil { if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify handle charge.refunded") logx.Errorf("err%+vdesc%s", err, "pay notify handle charge.refunded")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify handle charge.refunded") return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify handle charge.refunded")
// } }
// // ... handle other event types // ... handle other event types
// default: default:
// logx.Error("Unhandled event") logx.Error("Unhandled event")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type Unhandled") return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type Unhandled")
// } }
return resp.SetStatus(basic.CodeOK) return resp.SetStatus(basic.CodeOK)
} }
// 回调事件日志 // 回调事件日志
func (l *StripeWebhookLogic) HandlePayEventCreate(fsPayEvent *gmodel.FsPayEvent) error { func (l *StripeWebhookLogic) HandlePayEventCreate(fsPayEvent *gmodel.FsOrderTradeEvent) error {
_, err := gmodel.NewFsPayEventModel(l.svcCtx.MysqlConn).CreateOrUpdate(l.ctx, fsPayEvent) result := l.svcCtx.MysqlConn.Create(fsPayEvent)
return err return result.Error
} }
// 退款成功 // 退款成功
func (l *StripeWebhookLogic) HandleChargeRefunded(chargeRefunded *stripe.Charge) (err error) { func (l *StripeWebhookLogic) HandleChargeRefunded(chargeRefunded *stripe.Charge) (err error) {
// // 退款成功 // 退款成功
// if chargeRefunded.Status == "succeeded" { // if chargeRefunded.Status == "succeeded" {
// ctx := l.ctx // ctx := l.ctx
// err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error { // err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error {
@ -227,162 +241,27 @@ func (l *StripeWebhookLogic) HandleChargeRefunded(chargeRefunded *stripe.Charge)
// } // }
// 付款成功 // 付款成功
func (l *StripeWebhookLogic) HandlePaymentIntentSucceeded(paymentIntent *stripe.PaymentIntent) error { func (l *StripeWebhookLogic) HandleChargeSucceeded(charge *stripe.Charge, eventId string) error {
// orderSn, ok := paymentIntent.Metadata["order_sn"] // 支付成功
// if !ok || orderSn == "" { if charge.Status == "succeeded" {
// return errors.New("order_sn not found") model, ok := charge.Metadata["model"]
// } if !ok {
err := errors.New("model is empty")
// // 查询支付记录 logc.Errorf(l.ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", eventId, err)
// payModel := gmodel.NewFsPayModel(l.svcCtx.MysqlConn) return err
// rsbPay := payModel.RowSelectBuilder(nil) }
// rsbPay = rsbPay.Where("order_number = ?", orderSn).Where("pay_status = ?", constants.PAYSTATUS_UNSUCCESS) switch model {
// payInfo, err := payModel.FindOneByQuery(l.ctx, rsbPay, nil) case "product_order":
// if err != nil { res, err := l.svcCtx.Repositories.NewOrder.PaymentSuccessful(l.ctx, &repositories.PaymentSuccessfulReq{
// return err EventId: eventId,
// } PaymentMethod: "stripe",
Charge: charge,
// //订单信息 })
// orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(l.svcCtx.MysqlConn) if err != nil {
// orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn) return err
// fsOrderDetailModel := gmodel.NewFsOrderDetailModel(l.svcCtx.MysqlConn) }
// fsProductDesignModel := gmodel.NewFsProductDesignModel(l.svcCtx.MysqlConn) fmt.Println(res)
}
// rsbOrder := orderModel.RowSelectBuilder(nil) }
// rsbOrder = rsbOrder.Where("sn =?", orderSn).Preload("FsOrderDetails")
// rsbOrder = rsbOrder.Preload("FsOrderDetails", func(dbPreload *gorm.DB) *gorm.DB {
// return dbPreload.Table(fsOrderDetailModel.TableName()).Preload("FsOrderDetailTemplateInfo", func(dbPreload *gorm.DB) *gorm.DB {
// return dbPreload.Table(orderDetailTemplateModel.TableName()).Preload("FsProductDesignInfo", func(dbPreload *gorm.DB) *gorm.DB {
// return dbPreload.Table(fsProductDesignModel.TableName())
// })
// })
// })
// fsOrderRelInfo, err := orderModel.FindOneByQuery(l.ctx, rsbOrder, nil)
// if err != nil {
// return err
// }
// var designIds []int64
// var cartIds []int64
// if len(fsOrderRelInfo.FsOrderDetails) > 0 {
// for _, fsOrderDetail := range fsOrderRelInfo.FsOrderDetails {
// if fsOrderDetail.FsOrderDetailTemplateInfo.FsProductDesignInfo.Id != 0 {
// designIds = append(designIds, fsOrderDetail.FsOrderDetailTemplateInfo.FsProductDesignInfo.Id)
// }
// cartIds = append(cartIds, *fsOrderDetail.CartId)
// }
// }
// var nowTime int64 = time.Now().UTC().Unix()
// // 支付成功
// if paymentIntent.Status == "succeeded" {
// var card string
// var brand string
// if paymentIntent.LatestCharge.PaymentMethodDetails != nil {
// if paymentIntent.LatestCharge.PaymentMethodDetails.Card != nil {
// if paymentIntent.LatestCharge.PaymentMethodDetails.Card.Last4 != "" {
// card = paymentIntent.LatestCharge.PaymentMethodDetails.Card.Last4
// }
// if paymentIntent.LatestCharge.PaymentMethodDetails.Card.Brand != "" {
// brand = string(paymentIntent.LatestCharge.PaymentMethodDetails.Card.Brand)
// }
// }
// }
// ctx := l.ctx
// err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error {
// // 更新支付信息
// payModelT := gmodel.NewFsPayModel(connGorm)
// *payInfo.PayStatus = 1
// *payInfo.PayTime = nowTime
// *payInfo.CardNo = card
// *payInfo.Brand = brand
// *payInfo.TradeNo = paymentIntent.ID
// _, err = payModelT.RBCreateOrUpdate(ctx, payInfo)
// if err != nil {
// return err
// }
// // 更新设计数据
// productDesignModelT := gmodel.NewFsProductDesignModel(connGorm)
// productDesignModelTRSB := productDesignModelT.BuilderTrans(ctx, nil)
// var isPay int64 = 1
// err = productDesignModelT.RBUpdateByIds(productDesignModelTRSB, designIds, &gmodel.FsProductDesign{IsPay: &isPay})
// if err != nil {
// return err
// }
// var orderInfo = &gmodel.FsOrder{}
// var orderStatus int64
// var orderIsPartPay int64
// var orderPayedAmount int64
// var orderIsPayCompleted int64
// // 支付记录是首款
// if *payInfo.PayStage == int64(constants.PAYSTAGE_DEPOSIT) {
// orderStatus = int64(constants.STATUS_NEW_PART_PAY)
// orderIsPartPay = 1
// orderInfo.IsPartPay = &orderIsPartPay
// orderPayedAmount = paymentIntent.Amount
// // 删除购物车
// cartModelT := gmodel.NewFsCartModel(connGorm)
// cartModelTRSB := cartModelT.BuilderTrans(ctx, nil)
// err = cartModelT.RBDeleteCartsByIds(cartModelTRSB, cartIds)
// if err != nil {
// return err
// }
// }
// // 支付记录是尾款
// if *payInfo.PayStage == int64(constants.PAYSTAGE_REMAINING) {
// if *fsOrderRelInfo.Status < int64(constants.STATUS_NEW_PAY_COMPLETED) {
// orderStatus = int64(constants.STATUS_NEW_PAY_COMPLETED)
// }
// orderIsPayCompleted = 1
// orderInfo.IsPayCompleted = &orderIsPayCompleted
// orderPayedAmount = *fsOrderRelInfo.PayedAmount + paymentIntent.Amount
// }
// // 更新订单信息
// orderInfo.Id = fsOrderRelInfo.Id
// orderInfo.Status = &orderStatus
// orderInfo.Ptime = &nowTime
// orderInfo.PayedAmount = &orderPayedAmount
// orderModelT := gmodel.NewFsOrderModel(connGorm)
// err = orderModelT.RBUpdate(ctx, orderInfo)
// if err != nil {
// return err
// }
// return err
// })
// if err != nil {
// return err
// }
// //千人千面的处理
// // $renderServer = (new RenderService());
// // $renderServer->thousandsFacesV2($order->id);
// // //清除用户最新的设计
// // $cache = \Yii::$app->cache;
// // $cache->delete(CacheConfigHelper::LAST_DESIGN . $order->user_id);
// // //缓存最新订单编号
// // $cache->set(CacheConfigHelper::USER_ORDERNO . $order->user_id, $order->sn);
// // //查询用户邮箱信息
// // $user = \api\models\User::find()->where(['id' => $order->user_id])->one();
// // $redisData = [
// // 'key' => 'receipt_download',
// // 'param' => [
// // 'email' => $user->email,
// // 'order_id' => $order->id,
// // 'pay_id' => $pay->id,
// // 'type' => 1,//付款成功为1
// // ]
// // ];
// // Email::timely($redisData);
// }
// 订单记录
return nil return nil
} }

View File

@ -20,6 +20,7 @@ type ServiceContext struct {
MysqlConn *gorm.DB MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen AllModels *gmodel.AllModelsGen
Repositories *initalize.Repositories
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
@ -31,6 +32,9 @@ func NewServiceContext(c config.Config) *ServiceContext {
MysqlConn: conn, MysqlConn: conn,
SharedState: nil, SharedState: nil,
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)), AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: conn,
}),
} }
} }

View File

@ -11,18 +11,6 @@ type OrderRefundReq struct {
type OrderRefundRes struct { type OrderRefundRes struct {
} }
type OrderPaymentIntentReq struct {
Sn string `form:"sn"` //订单编号
DeliveryMethod int64 `form:"delivery_method"` //发货方式
AddressId int64 `form:"address_id"` //地址id
PayMethod int64 `form:"pay_method"` //支付方式
}
type OrderPaymentIntentRes struct {
RedirectUrl string `json:"redirect_url"`
ClientSecret string `json:"clientSecret"`
}
type StripeWebhookReq struct { type StripeWebhookReq struct {
Payload []byte `json:"base_byte_slice,optional"` Payload []byte `json:"base_byte_slice,optional"`
StripeSignature string `json:"Stripe-Signature"` StripeSignature string `json:"Stripe-Signature"`
@ -52,10 +40,10 @@ type File struct {
} }
type Meta struct { type Meta struct {
TotalCount int64 `json:"totalCount"` TotalCount int64 `json:"total_count"`
PageCount int64 `json:"pageCount"` PageCount int64 `json:"page_count"`
CurrentPage int `json:"currentPage"` CurrentPage int `json:"current_page"`
PerPage int `json:"perPage"` PerPage int `json:"per_page"`
} }
// Set 设置Response的Code和Message值 // Set 设置Response的Code和Message值

View File

@ -106,7 +106,7 @@ func (l *GetProductTemplateTagsLogic) GetProductTemplateTags(req *types.GetProdu
for templateTag, _ := range mapMaterialTemplateTagColors { for templateTag, _ := range mapMaterialTemplateTagColors {
templateTagNameList = append(templateTagNameList, templateTag) templateTagNameList = append(templateTagNameList, templateTag)
} }
productTemplateTags, err = l.svcCtx.AllModels.FsProductTemplateTags.GetListByTagNames(l.ctx, templateTagNameList, req.Limit, 1, "id DESC") productTemplateTags, err = l.svcCtx.AllModels.FsProductTemplateTags.GetListByTagNames(l.ctx, templateTagNameList, len(templateTagNameList), 1, "id DESC")
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get template tags") return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get template tags")
@ -135,6 +135,7 @@ func (l *GetProductTemplateTagsLogic) GetProductTemplateTags(req *types.GetProdu
for k, v := range productTemplateTags { for k, v := range productTemplateTags {
if templateTagStr == *v.TemplateTag { if templateTagStr == *v.TemplateTag {
productTemplateTags[k], productTemplateTags[index] = productTemplateTags[index], productTemplateTags[k] productTemplateTags[k], productTemplateTags[index] = productTemplateTags[index], productTemplateTags[k]
break
} }
} }
} }

View File

@ -11,4 +11,22 @@ type Config struct {
SourceMysql string SourceMysql string
Auth types.Auth Auth types.Auth
ReplicaId uint64 ReplicaId uint64
AWS struct {
S3 struct {
Credentials struct {
AccessKeyID string
Secret string
Token string
}
}
}
BLMService struct {
Url string
LogoCombine struct {
Url string
}
}
Unity struct {
Host string
}
} }

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/product/internal/logic"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
)
func CalculateProductPriceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CalculateProductPriceReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewCalculateProductPriceLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.CalculateProductPrice(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/product/internal/logic"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
)
func GetProductStepPriceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetProductStepPriceReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewGetProductStepPriceLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.GetProductStepPrice(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -72,6 +72,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/product/get_price_by_pid", Path: "/api/product/get_price_by_pid",
Handler: GetPriceByPidHandler(serverCtx), Handler: GetPriceByPidHandler(serverCtx),
}, },
{
Method: http.MethodGet,
Path: "/api/product/get_product_step_price",
Handler: GetProductStepPriceHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/product/calculate_product_price",
Handler: CalculateProductPriceHandler(serverCtx),
},
{ {
Method: http.MethodGet, Method: http.MethodGet,
Path: "/api/product/get_size_by_pid", Path: "/api/product/get_size_by_pid",

View File

@ -0,0 +1,101 @@
package logic
import (
"encoding/json"
"errors"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"gorm.io/gorm"
"context"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CalculateProductPriceLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCalculateProductPriceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CalculateProductPriceLogic {
return &CalculateProductPriceLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *CalculateProductPriceLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *CalculateProductPriceLogic) CalculateProductPrice(req *types.CalculateProductPriceReq, userinfo *auth.UserInfo) (resp *basic.Response) {
if req.ProductId <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:product id")
}
if req.SizeId <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:size id")
}
if req.PurchaseQuantity <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:purchase quantity")
}
//获取产品信息(只是获取id)
_, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, req.ProductId, "id")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the product is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product info")
}
//根据产品跟尺寸获取模型价格信息
modelInfo, err := l.svcCtx.AllModels.FsProductModel3d.FindOneByProductIdSizeIdTag(l.ctx, req.ProductId, req.SizeId, constants.TAG_MODEL, "id,step_price")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "model info is not exists")
}
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get model info")
}
var stepPrice gmodel.StepPriceJsonStruct
if modelInfo.StepPrice != nil && len(*modelInfo.StepPrice) != 0 {
if err = json.Unmarshal(*modelInfo.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse step price")
}
}
//配件
fittingPrice := int64(0)
if req.FittingId > 0 {
fittingInfo, err := l.svcCtx.AllModels.FsProductModel3d.FindOne(l.ctx, req.FittingId, "id,price")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "fitting info is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get fitting info")
}
fittingPrice = *fittingInfo.Price
}
totalPrice, itemPrice, err := l.svcCtx.Repositories.NewShoppingCart.CaculateStepPrice(req.PurchaseQuantity, stepPrice, fittingPrice)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to calculate product price ")
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.CalculateProductPriceRsp{
ItemPrice: format.CentitoDollar(itemPrice, 3),
TotalPrice: format.CentitoDollarWithNoHalfAdjust(totalPrice, 2),
PurchaseQuantity: req.PurchaseQuantity,
})
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *CalculateProductPriceLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -2,12 +2,9 @@ package logic
import ( import (
"context" "context"
"errors"
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
"gorm.io/gorm"
"fusenapi/server/product/internal/svc" "fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types" "fusenapi/server/product/internal/types"
@ -33,18 +30,18 @@ func (l *GetLastProductDesignLogic) GetLastProductDesign(req *types.Request, use
return resp.SetStatusAddMessage(basic.CodeUnAuth, "please sign in") return resp.SetStatusAddMessage(basic.CodeUnAuth, "please sign in")
} }
//获取用户信息 //获取用户信息
user, err := l.svcCtx.AllModels.FsUser.FindUserById(l.ctx, userinfo.UserId) // user, err := l.svcCtx.AllModels.FsUser.FindUserById(l.ctx, userinfo.UserId)
if err != nil { // if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { // if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeUnAuth, "user not found") // return resp.SetStatusWithMessage(basic.CodeUnAuth, "user not found")
} // }
logx.Error(err) // logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info") // return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info")
} // }
//若没打开了个性化渲染按钮 // //若没打开了个性化渲染按钮
if *user.IsOpenRender != 1 { // if *user.IsOpenRender != 1 {
return resp.SetStatusWithMessage(basic.CodeOK, "success:IsOpenRender switch is closed") // return resp.SetStatusWithMessage(basic.CodeOK, "success:IsOpenRender switch is closed")
} // }
//查询用户最近下单成功的数据 //查询用户最近下单成功的数据
// orderInfo, err := l.svcCtx.AllModels.FsOrder.FindLastSuccessOneOrder(l.ctx, user.Id, int64(constants.STATUS_NEW_NOT_PAY)) // orderInfo, err := l.svcCtx.AllModels.FsOrder.FindLastSuccessOneOrder(l.ctx, user.Id, int64(constants.STATUS_NEW_NOT_PAY))
// if err != nil { // if err != nil {

View File

@ -377,8 +377,8 @@ func (l *GetProductInfoLogic) GetProductInfo(req *types.GetProductInfoReq, useri
logx.Error(err) logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info") return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info")
} }
isLowRendering = *user.IsLowRendering > 0 isLowRendering = true
isRemoveBg = *user.IsRemoveBg > 0 isRemoveBg = true
lastDesign = l.getLastDesign(user) lastDesign = l.getLastDesign(user)
} }
var renderDesign interface{} var renderDesign interface{}

View File

@ -12,12 +12,13 @@ import (
"fusenapi/utils/basic" "fusenapi/utils/basic"
"fusenapi/utils/format" "fusenapi/utils/format"
"fusenapi/utils/image" "fusenapi/utils/image"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"gorm.io/gorm"
"math" "math"
"sort" "sort"
"strings" "strings"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"gorm.io/gorm"
) )
type GetProductListLogic struct { type GetProductListLogic struct {
@ -163,7 +164,7 @@ func (l *GetProductListLogic) GetProductList(req *types.GetProductListReq, useri
UserId: user.Id, UserId: user.Id,
} }
if user.Id != 0 { if user.Id != 0 {
r.IsThousandFace = int(*user.IsThousandFace) r.IsThousandFace = 1
} }
image.ThousandFaceImageFormat(&r) image.ThousandFaceImageFormat(&r)
item.Cover = r.Cover item.Cover = r.Cover

View File

@ -0,0 +1,137 @@
package logic
import (
"context"
"encoding/json"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"gorm.io/gorm"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetProductStepPriceLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetProductStepPriceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductStepPriceLogic {
return &GetProductStepPriceLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *GetProductStepPriceLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *GetProductStepPriceLogic) GetProductStepPrice(req *types.GetProductStepPriceReq, userinfo *auth.UserInfo) (resp *basic.Response) {
if req.ProductId <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:product id")
}
//获取产品信息(只是获取id)
_, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, req.ProductId, "id")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the product is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product info")
}
//查询产品价格
modelPriceList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByProductIdTag(l.ctx, req.ProductId, constants.TAG_MODEL, "id,size_id,part_id,step_price,packed_unit")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get model price list")
}
fittingIds := make([]int64, 0, len(modelPriceList))
for _, v := range modelPriceList {
if *v.PartId > 0 {
fittingIds = append(fittingIds, *v.PartId)
}
}
//查询配件价格列表
fittingPriceList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIdsTag(l.ctx, fittingIds, constants.TAG_PARTS, "id,price,packed_unit")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get fitting price list")
}
mapFitting := make(map[int64]gmodel.FsProductModel3d)
for _, v := range fittingPriceList {
mapFitting[v.Id] = v
}
//遍历处理模型价格
mapRsp := make(map[string]interface{})
for _, modelPriceInfo := range modelPriceList {
var stepPrice gmodel.StepPriceJsonStruct
if err = json.Unmarshal(*modelPriceInfo.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse step price json")
}
rangeLen := len(stepPrice.PriceRange)
if rangeLen == 0 {
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("step price is not set:%d", modelPriceInfo.Id))
}
//最小单价
minPrice := stepPrice.PriceRange[rangeLen-1].Price
//最大单价
maxPrice := stepPrice.PriceRange[0].Price
//购买数步进基数
stepPurchaseQuantity := *modelPriceInfo.PackedUnit
//购买数步进基数描述
stepPurchaseQuantityDescription := "主体装箱数为步进基数"
if *modelPriceInfo.PartId > 0 {
fittingPriceInfo, ok := mapFitting[*modelPriceInfo.PartId]
if !ok {
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("fitting price is not exists:%d", *modelPriceInfo.PartId))
}
//最小价格要加配件
minPrice += *fittingPriceInfo.Price
//如果配件装箱基数比主体大,则基数以配件为主
if *fittingPriceInfo.PackedUnit > stepPurchaseQuantity {
stepPurchaseQuantity = *fittingPriceInfo.PackedUnit
stepPurchaseQuantityDescription = "配件装箱数为步进基数"
}
}
stepRange := make([]interface{}, 0, rangeLen)
for rIndex, rangeInfo := range stepPrice.PriceRange {
//最后一个
if rIndex+1 == rangeLen {
stepRange = append(stepRange, map[string]interface{}{
"range_description": fmt.Sprintf(">=%s Units", format.NumToStringWithThousandthPercentile(rangeInfo.StartQuantity)),
"item_price": format.CentitoDollar(rangeInfo.Price, 3),
})
break
}
stepRange = append(stepRange, map[string]interface{}{
"range_description": fmt.Sprintf("%s-%s Units", format.NumToStringWithThousandthPercentile(rangeInfo.StartQuantity), format.NumToStringWithThousandthPercentile(rangeInfo.EndQuantity)),
"item_price": format.CentitoDollar(rangeInfo.Price, 3),
})
}
mapRsp[fmt.Sprintf("_%d", *modelPriceInfo.SizeId)] = map[string]interface{}{
"step_purchase_quantity": stepPurchaseQuantity,
"step_purchase_quantity_description": stepPurchaseQuantityDescription,
"min_price": minPrice,
"max_price": maxPrice,
"step_range": stepRange,
"min_buy_units_quantity": stepPrice.MinBuyUnitsNum,
}
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", mapRsp)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *GetProductStepPriceLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -77,8 +77,8 @@ func (l *GetRenderSettingByPidLogic) GetRenderSettingByPid(req *types.GetRenderS
logx.Error(err) logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info") return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info")
} }
isLowRendering = *user.IsLowRendering > 0 isLowRendering = true
isRemoveBg = *user.IsRemoveBg > 0 isRemoveBg = true
lastDesign, err = l.checkLastDesignExists(user.Id) lastDesign, err = l.checkLastDesignExists(user.Id)
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)

View File

@ -59,7 +59,10 @@ func (l *GetSizeByPidLogic) GetSizeByPid(req *types.GetSizeByPidReq, userinfo *a
} else { } else {
//根据模板找到模型sizeId //根据模板找到模型sizeId
defaultModel3d, err := l.svcCtx.AllModels.FsProductModel3d.FindOne(l.ctx, *defaultTemplate.ModelId, "size_id") defaultModel3d, err := l.svcCtx.AllModels.FsProductModel3d.FindOne(l.ctx, *defaultTemplate.ModelId, "size_id")
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "the template`s model is not exists ")
}
logx.Error(err) logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get default model ") return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get default model ")
} }

View File

@ -1,16 +1,10 @@
package logic package logic
import ( import (
"context"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
"fusenapi/utils/format"
"fusenapi/utils/step_price" "context"
"strings"
"fusenapi/server/product/internal/svc" "fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types" "fusenapi/server/product/internal/types"
@ -32,157 +26,18 @@ func NewGetSizeByProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *
} }
} }
// 获取分类下的产品以及尺寸 // 处理进入前逻辑w,r
// func (l *GetSizeByProductLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *GetSizeByProductLogic) GetSizeByProduct(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) { func (l *GetSizeByProductLogic) GetSizeByProduct(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) {
if userinfo.GetIdType() != auth.IDTYPE_User { // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
return resp.SetStatusWithMessage(basic.CodeUnAuth, "please sign in first") // userinfo 传入值时, 一定不为null
}
//获取所有网站目录 return resp.SetStatus(basic.CodeOK)
tagsModel := gmodel.NewFsTagsModel(l.svcCtx.MysqlConn)
tagsList, err := tagsModel.GetAllByLevel(l.ctx, constants.TYPE_WEBSITE)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get website tags")
}
if len(tagsList) == 0 {
return resp.SetStatusWithMessage(basic.CodeOK, "tag list is null")
}
tagIds := make([]int64, 0, len(tagsList))
for _, v := range tagsList {
tagIds = append(tagIds, v.Id)
}
//获取这些类型的产品
productModel := gmodel.NewFsProductModel(l.svcCtx.MysqlConn)
productList, err := productModel.GetProductListByIds(l.ctx, tagIds, "sort-desc")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get tag product list")
}
productIds := make([]int64, 0, len(productList))
for _, v := range productList {
productIds = append(productIds, v.Id)
}
productSizeModel := gmodel.NewFsProductSizeModel(l.svcCtx.MysqlConn)
productSizeList, err := productSizeModel.GetAllByProductIds(l.ctx, productIds, "sort DESC")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product size list")
}
sizeIds := make([]int64, 0, len(productSizeList))
for _, v := range productSizeList {
sizeIds = append(sizeIds, v.Id)
}
//获取价格列表
productPriceModel := gmodel.NewFsProductPriceModel(l.svcCtx.MysqlConn)
productPriceList, err := productPriceModel.GetPriceListByProductIdsSizeIds(l.ctx, productIds, sizeIds)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product proce list")
}
mapProductPrice := make(map[string]gmodel.FsProductPrice)
for _, v := range productPriceList {
mapProductPrice[fmt.Sprintf("%d_%d", *v.ProductId, *v.SizeId)] = v
}
//组装返回
list := make([]types.GetSizeByProductRsp, 0, len(tagsList))
for _, tag := range tagsList {
//获取第一层子类
firstChildrenList, err := l.GetFirstChildrenList(tag, productList, productSizeList, mapProductPrice)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get first level children list")
}
data := types.GetSizeByProductRsp{
Id: tag.Id,
Name: *tag.Title,
Children: firstChildrenList,
}
list = append(list, data)
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", list)
} }
// 第一层子层 // 处理逻辑后 w,r 如:重定向, resp 必须重新处理
func (l *GetSizeByProductLogic) GetFirstChildrenList(tag gmodel.FsTags, productList []gmodel.FsProduct, productSizeList []gmodel.FsProductSize, mapProductPrice map[string]gmodel.FsProductPrice) (childrenList []types.Children, err error) { // func (l *GetSizeByProductLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
childrenList = make([]types.Children, 0, len(productList)) // // httpx.OkJsonCtx(r.Context(), w, resp)
for _, product := range productList { // }
if *product.Type != tag.Id {
continue
}
childrenObjList, err := l.GetSecondChildrenList(product, productSizeList, mapProductPrice)
if err != nil {
return nil, err
}
//获取第二层子类
data := types.Children{
Id: product.Id,
Name: *product.Title,
Cycle: int(*product.DeliveryDays + *product.ProduceDays),
ChildrenList: childrenObjList,
}
childrenList = append(childrenList, data)
}
return
}
// 第2层子层
func (l *GetSizeByProductLogic) GetSecondChildrenList(product gmodel.FsProduct, productSizeList []gmodel.FsProductSize, mapProductPrice map[string]gmodel.FsProductPrice) (childrenObjList []types.ChildrenObj, err error) {
childrenObjList = make([]types.ChildrenObj, 0, len(productSizeList))
for _, productSize := range productSizeList {
if product.Id != *productSize.ProductId {
continue
}
priceList := make([]types.PriceObj, 0, len(productSizeList))
price, ok := mapProductPrice[fmt.Sprintf("%d_%d", *productSize.ProductId, productSize.Id)]
//无对应尺寸价格
if !ok {
priceList = []types.PriceObj{
{Num: 1, Price: 0},
{Num: 1, Price: 0},
{Num: 1, Price: 0},
}
childrenObjList = append(childrenObjList, types.ChildrenObj{
Id: productSize.Id,
Name: *productSize.Capacity,
PriceList: priceList,
})
continue
}
if price.StepNum == nil || price.StepPrice == nil {
continue
}
*price.StepNum = strings.Trim(*price.StepNum, " ")
*price.StepPrice = strings.Trim(*price.StepPrice, " ")
//阶梯数量切片
stepNum, err := format.StrSlicToIntSlice(strings.Split(*price.StepNum, ","))
if err != nil {
return nil, err
}
//阶梯价格切片
stepPrice, err := format.StrSlicToIntSlice(strings.Split(*price.StepPrice, ","))
if err != nil {
return nil, err
}
if len(stepNum) == 0 || len(stepPrice) == 0 {
return nil, errors.New(fmt.Sprintf("stepNum count or stepPrice count is empty: product size id :%d ,product price id :%d", productSize.Id, price.Id))
}
index := 0
// 最小购买数量小于 最大阶梯数量+5
for int(*price.MinBuyNum) < (stepNum[len(stepNum)-1]+5) && index < 3 {
priceList = append(priceList, types.PriceObj{
Num: int(*price.MinBuyNum * *price.EachBoxNum),
Price: step_price.GetStepPrice(int(*price.MinBuyNum), stepNum, stepPrice),
})
*price.MinBuyNum++
index++
}
data := types.ChildrenObj{
Id: productSize.Id,
Name: *productSize.Capacity,
PriceList: priceList,
}
childrenObjList = append(childrenObjList, data)
}
return
}

View File

@ -9,6 +9,7 @@ import (
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
"fusenapi/utils/image" "fusenapi/utils/image"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -75,7 +76,7 @@ func (l *GetSuccessRecommandLogic) GetSuccessRecommand(req *types.GetSuccessReco
UserId: user.Id, UserId: user.Id,
} }
if user.Id > 0 { if user.Id > 0 {
r.IsThousandFace = int(*user.IsThousandFace) r.IsThousandFace = int(1)
} }
image.ThousandFaceImageFormat(&r) image.ThousandFaceImageFormat(&r)
data.Cover = r.Cover data.Cover = r.Cover

View File

@ -8,9 +8,10 @@ import (
"fusenapi/utils/basic" "fusenapi/utils/basic"
"fusenapi/utils/format" "fusenapi/utils/format"
"fusenapi/utils/image" "fusenapi/utils/image"
"gorm.io/gorm"
"strings" "strings"
"gorm.io/gorm"
"fusenapi/server/product/internal/svc" "fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types" "fusenapi/server/product/internal/types"
@ -83,7 +84,7 @@ func (l *OtherProductListLogic) OtherProductList(req *types.OtherProductListReq,
UserId: user.Id, UserId: user.Id,
} }
if user.Id > 0 { if user.Id > 0 {
r.IsThousandFace = int(*user.IsThousandFace) r.IsThousandFace = 1
} }
image.ThousandFaceImageFormat(r) image.ThousandFaceImageFormat(r)
v.Cover = r.Cover v.Cover = r.Cover

View File

@ -5,6 +5,9 @@ import (
"fmt" "fmt"
"fusenapi/server/product/internal/config" "fusenapi/server/product/internal/config"
"fusenapi/shared" "fusenapi/shared"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"net/http" "net/http"
"fusenapi/initalize" "fusenapi/initalize"
@ -20,13 +23,26 @@ type ServiceContext struct {
MysqlConn *gorm.DB MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen AllModels *gmodel.AllModelsGen
Repositories *initalize.Repositories
AwsSession *session.Session
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
conn := initalize.InitMysql(c.SourceMysql)
config := aws.Config{
Credentials: credentials.NewStaticCredentials(c.AWS.S3.Credentials.AccessKeyID, c.AWS.S3.Credentials.Secret, c.AWS.S3.Credentials.Token),
}
return &ServiceContext{ return &ServiceContext{
Config: c, Config: c,
MysqlConn: initalize.InitMysql(c.SourceMysql), MysqlConn: initalize.InitMysql(c.SourceMysql),
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)), AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
AwsSession: session.Must(session.NewSession(&config)),
Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: conn,
BLMServiceUrl: &c.BLMService.Url,
AwsSession: session.Must(session.NewSession(&config)),
}),
} }
} }

View File

@ -331,6 +331,23 @@ type PriceItem struct {
Price int64 `json:"price"` Price int64 `json:"price"`
} }
type GetProductStepPriceReq struct {
ProductId int64 `form:"product_id"`
}
type CalculateProductPriceReq struct {
ProductId int64 `json:"product_id"`
SizeId int64 `json:"size_id"`
FittingId int64 `json:"fitting_id,optional"`
PurchaseQuantity int64 `json:"purchase_quantity"`
}
type CalculateProductPriceRsp struct {
ItemPrice string `json:"item_price"`
TotalPrice string `json:"total_price"`
PurchaseQuantity int64 `json:"purchase_quantity"`
}
type GetSizeByPidReq struct { type GetSizeByPidReq struct {
Pid string `form:"pid"` Pid string `form:"pid"`
TemplateTag string `form:"template_tag"` TemplateTag string `form:"template_tag"`
@ -440,10 +457,10 @@ type File struct {
} }
type Meta struct { type Meta struct {
TotalCount int64 `json:"totalCount"` TotalCount int64 `json:"total_count"`
PageCount int64 `json:"pageCount"` PageCount int64 `json:"page_count"`
CurrentPage int `json:"currentPage"` CurrentPage int `json:"current_page"`
PerPage int `json:"perPage"` PerPage int `json:"per_page"`
} }
// Set 设置Response的Code和Message值 // Set 设置Response的Code和Message值

View File

@ -10,6 +10,8 @@ import (
"fusenapi/server/shopping-cart/internal/types" "fusenapi/server/shopping-cart/internal/types"
"fusenapi/utils/auth" "fusenapi/utils/auth"
"fusenapi/utils/basic" "fusenapi/utils/basic"
"fusenapi/utils/file"
"fusenapi/utils/hash"
"gorm.io/gorm" "gorm.io/gorm"
"time" "time"
@ -51,6 +53,31 @@ func (l *AddToCartLogic) AddToCart(req *types.AddToCartReq, userinfo *auth.UserI
if cartCount >= 100 { if cartCount >= 100 {
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "sorry,the count of your carts can`t greater than 100") return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "sorry,the count of your carts can`t greater than 100")
} }
if req.RenderImage != "" {
//上传base64文件
// 上传文件
var upload = file.Upload{
Ctx: l.ctx,
MysqlConn: l.svcCtx.MysqlConn,
AwsSession: l.svcCtx.AwsSession,
}
uploadRes, err := upload.UploadFileByBase64(&file.UploadBaseReq{
Source: "webGl render image",
FileHash: hash.JsonHashKey(req.RenderImage),
FileData: req.RenderImage,
Metadata: "",
UploadBucket: 1,
ApiType: 2,
UserId: userinfo.UserId,
GuestId: userinfo.GuestId,
FileByte: nil,
})
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeFileUploadErr, "failed to upload webGl render image")
}
req.RenderImage = uploadRes.ResourceUrl
}
//获取产品是否存在 //获取产品是否存在
productInfo, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, req.ProductId) productInfo, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, req.ProductId)
if err != nil { if err != nil {

View File

@ -2,9 +2,9 @@ package logic
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"fusenapi/constants"
"fusenapi/model/gmodel" "fusenapi/model/gmodel"
"fusenapi/server/shopping-cart/internal/svc" "fusenapi/server/shopping-cart/internal/svc"
"fusenapi/server/shopping-cart/internal/types" "fusenapi/server/shopping-cart/internal/types"
@ -53,7 +53,7 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
//获取购物车列表 //获取购物车列表
carts, _, err := l.svcCtx.AllModels.FsShoppingCart.GetAllCartsByParam(l.ctx, gmodel.GetAllCartsByParamReq{ carts, _, err := l.svcCtx.AllModels.FsShoppingCart.GetAllCartsByParam(l.ctx, gmodel.GetAllCartsByParamReq{
Ids: cartIds, Ids: cartIds,
Fields: "id,size_id,product_id,fitting_id", Fields: "id,size_id,product_id,fitting_id,model_id",
UserId: userinfo.UserId, UserId: userinfo.UserId,
Page: 1, Page: 1,
Limit: len(cartIds), Limit: len(cartIds),
@ -67,33 +67,24 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
} }
sizeIds := make([]int64, 0, len(carts)) sizeIds := make([]int64, 0, len(carts))
productIds := make([]int64, 0, len(carts)) productIds := make([]int64, 0, len(carts))
fittingIds := make([]int64, 0, len(carts)) modelIds := make([]int64, 0, len(carts)) //模型+配件
for _, v := range carts { for _, v := range carts {
sizeIds = append(sizeIds, *v.SizeId) sizeIds = append(sizeIds, *v.SizeId)
productIds = append(productIds, *v.ProductId) productIds = append(productIds, *v.ProductId)
modelIds = append(modelIds, *v.ModelId)
if *v.FittingId > 0 { if *v.FittingId > 0 {
fittingIds = append(fittingIds, *v.FittingId) modelIds = append(modelIds, *v.FittingId)
} }
} }
//根据sizeid获取价格列表
priceList, err := l.svcCtx.AllModels.FsProductPrice.GetPriceListByProductIdsSizeIds(l.ctx, productIds, sizeIds)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get price list")
}
mapPrice := make(map[string]gmodel.FsProductPrice)
for _, v := range priceList {
mapPrice[fmt.Sprintf("%d_%d", *v.ProductId, *v.SizeId)] = v
}
//获取配件列表(只有id跟价格) //获取配件列表(只有id跟价格)
fittingList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIdsTag(l.ctx, fittingIds, constants.TAG_PARTS, "id,price") modelList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIds(l.ctx, modelIds, "id,step_price,price")
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get fitting list") return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get model list")
} }
mapFitting := make(map[int64]int64) mapModel := make(map[int64]gmodel.FsProductModel3d)
for _, v := range fittingList { for _, v := range modelList {
mapFitting[v.Id] = *v.Price mapModel[v.Id] = v
} }
//开始计算价格 //开始计算价格
calculateResultList := make([]types.CalculateResultItem, 0, len(req.CalculateList)) calculateResultList := make([]types.CalculateResultItem, 0, len(req.CalculateList))
@ -102,9 +93,16 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
err = l.svcCtx.MysqlConn.Transaction(func(tx *gorm.DB) error { err = l.svcCtx.MysqlConn.Transaction(func(tx *gorm.DB) error {
shoppingCartModel := gmodel.NewFsShoppingCartModel(tx) shoppingCartModel := gmodel.NewFsShoppingCartModel(tx)
for _, cart := range carts { for _, cart := range carts {
sizePrice, ok := mapPrice[fmt.Sprintf("%d_%d", *cart.ProductId, *cart.SizeId)] modelInfo, ok := mapModel[*cart.ModelId]
if !ok { if !ok {
return errors.New(fmt.Sprintf("there carts contain some one which have no price info:%d_%d", *cart.ProductId, *cart.SizeId)) return err
}
var stepPrice gmodel.StepPriceJsonStruct
if modelInfo.StepPrice != nil && len(*modelInfo.StepPrice) != 0 {
if err = json.Unmarshal(*modelInfo.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return err
}
} }
//请求的数量 //请求的数量
reqPurchaseQuantity := mapCalculateQuantity[cart.Id].PurchaseQuantity reqPurchaseQuantity := mapCalculateQuantity[cart.Id].PurchaseQuantity
@ -115,16 +113,15 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
//如果有配件,单价也要加入配件价格 //如果有配件,单价也要加入配件价格
fittingPrice := int64(0) fittingPrice := int64(0)
if *cart.FittingId > 0 { if *cart.FittingId > 0 {
if fPrice, ok := mapFitting[*cart.FittingId]; ok { if fittingInfo, ok := mapModel[*cart.FittingId]; ok {
fittingPrice = fPrice fittingPrice = *fittingInfo.Price
} else { } else {
return errors.New(fmt.Sprintf("cart contain some one witch lose fitting:%d", *cart.FittingId)) return errors.New(fmt.Sprintf("cart contain some one witch lose fitting:%d", *cart.FittingId))
} }
} }
//计算价格 //计算价格
itemPrice, totalPrice, _, _, err := l.svcCtx.Repositories.NewShoppingCart.CaculateCartPrice(reqPurchaseQuantity, &sizePrice, fittingPrice) totalPrice, itemPrice, err := l.svcCtx.Repositories.NewShoppingCart.CaculateStepPrice(reqPurchaseQuantity, stepPrice, fittingPrice)
if err != nil { if err != nil {
logx.Error(err)
return err return err
} }
calculateResultList = append(calculateResultList, types.CalculateResultItem{ calculateResultList = append(calculateResultList, types.CalculateResultItem{
@ -149,6 +146,7 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
return nil return nil
}) })
if err != nil { if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, err.Error()) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, err.Error())
} }
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.CalculateCartPriceRsp{ return resp.SetStatusWithMessage(basic.CodeOK, "success", types.CalculateCartPriceRsp{

View File

@ -41,37 +41,28 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
if !userinfo.IsUser() { if !userinfo.IsUser() {
return resp.SetStatusWithMessage(basic.CodeUnAuth, "please sign in") return resp.SetStatusWithMessage(basic.CodeUnAuth, "please sign in")
} }
if req.CurrentPage <= 0 { currentPage := constants.DEFAULT_PAGE
req.CurrentPage = constants.DEFAULT_PAGE
}
limit := 300 limit := 300
//获取用户购物车列表 //获取用户购物车列表
var cartIds []int64
if req.CartId > 0 {
cartIds = append(cartIds, req.CartId)
}
carts, total, err := l.svcCtx.AllModels.FsShoppingCart.GetAllCartsByParam(l.ctx, gmodel.GetAllCartsByParamReq{ carts, total, err := l.svcCtx.AllModels.FsShoppingCart.GetAllCartsByParam(l.ctx, gmodel.GetAllCartsByParamReq{
Ids: cartIds,
UserId: userinfo.UserId, UserId: userinfo.UserId,
Sort: "id DESC", Sort: "id DESC",
Page: req.CurrentPage, Page: currentPage,
Limit: limit, Limit: limit,
}) })
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "system err:failed to get your shopping carts") return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "system err:failed to get your shopping carts")
} }
if len(carts) == 0 {
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetCartsRsp{
Meta: types.Meta{
TotalCount: total,
PageCount: int64(math.Ceil(float64(total) / float64(limit))),
CurrentPage: req.CurrentPage,
PerPage: limit,
},
CartList: nil,
})
}
var ( var (
mapSize = make(map[int64]gmodel.FsProductSize) mapSize = make(map[int64]gmodel.FsProductSize)
mapModel = make(map[int64]gmodel.FsProductModel3d) mapModel = make(map[int64]gmodel.FsProductModel3d)
mapTemplate = make(map[int64]gmodel.FsProductTemplateV2) mapTemplate = make(map[int64]gmodel.FsProductTemplateV2)
mapSizePrice = make(map[string]gmodel.FsProductPrice)
mapProduct = make(map[int64]gmodel.FsProduct) mapProduct = make(map[int64]gmodel.FsProduct)
mapResourceMetadata = make(map[string]interface{}) mapResourceMetadata = make(map[string]interface{})
) )
@ -81,7 +72,6 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
MapSize: mapSize, MapSize: mapSize,
MapModel: mapModel, MapModel: mapModel,
MapTemplate: mapTemplate, MapTemplate: mapTemplate,
MapSizePrice: mapSizePrice,
MapProduct: mapProduct, MapProduct: mapProduct,
MapResourceMetadata: mapResourceMetadata, MapResourceMetadata: mapResourceMetadata,
}) })
@ -109,21 +99,34 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
list := make([]types.CartItem, 0, len(carts)) list := make([]types.CartItem, 0, len(carts))
for _, cart := range carts { for _, cart := range carts {
snapShot := mapSnapshot[cart.Id] snapShot := mapSnapshot[cart.Id]
sizePrice, ok := mapSizePrice[fmt.Sprintf("%d_%d", *cart.ProductId, *cart.SizeId)] modelInfo, ok := mapModel[*cart.ModelId]
if !ok { if !ok {
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("the size`s price info is not exists:%d_%d", *cart.ProductId, *cart.SizeId)) return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("the size`s model info is not exists:%d_%d", *cart.ProductId, *cart.SizeId))
} }
var stepPrice gmodel.StepPriceJsonStruct
if modelInfo.StepPrice != nil && len(*modelInfo.StepPrice) != 0 {
if err = json.Unmarshal(*modelInfo.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeJsonErr, fmt.Sprintf("failed to parse model step price:%d", *cart.ModelId))
}
}
//购买数量步进量
stepPurchaseQuantity := *modelInfo.PackedUnit
//如果有配件,单价也要加入配件价格 //如果有配件,单价也要加入配件价格
fittingPrice := int64(0) fittingPrice := int64(0)
if *cart.FittingId > 0 { if *cart.FittingId > 0 {
if curFittingInfo, ok := mapModel[*cart.FittingId]; ok { curFittingInfo, ok := mapModel[*cart.FittingId]
fittingPrice = *curFittingInfo.Price if !ok {
} else {
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("cart contain some one witch lose fitting:%d", *cart.FittingId)) return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("cart contain some one witch lose fitting:%d", *cart.FittingId))
} }
fittingPrice = *curFittingInfo.Price
//取大的为步进量基数
if *curFittingInfo.PackedUnit > stepPurchaseQuantity {
stepPurchaseQuantity = *curFittingInfo.PackedUnit
} }
//计算价格 }
itemPrice, totalPrice, _, _, err := l.svcCtx.Repositories.NewShoppingCart.CaculateCartPrice(*cart.PurchaseQuantity, &sizePrice, fittingPrice) //计算阶梯价格
totalPrice, itemPrice, err := l.svcCtx.Repositories.NewShoppingCart.CaculateStepPrice(*cart.PurchaseQuantity, stepPrice, fittingPrice)
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, err.Error()) return resp.SetStatusWithMessage(basic.CodeServiceErr, err.Error())
@ -152,6 +155,10 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
productCoverMetadata = metadata productCoverMetadata = metadata
} }
} }
templateTag := ""
if templateInfo, ok := mapTemplate[*cart.TemplateId]; ok {
templateTag = *templateInfo.TemplateTag
}
item := types.CartItem{ item := types.CartItem{
CartId: cart.Id, CartId: cart.Id,
ProductInfo: types.ProductInfo{ ProductInfo: types.ProductInfo{
@ -183,10 +190,12 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
Slogan: snapShot.UserDiyInformation.Slogan, Slogan: snapShot.UserDiyInformation.Slogan,
}, },
PurchaseQuantity: *cart.PurchaseQuantity, PurchaseQuantity: *cart.PurchaseQuantity,
MinPurchaseQuantity: *sizePrice.EachBoxNum * (*sizePrice.MinBuyNum), MinPurchaseQuantity: stepPrice.MinBuyUnitsNum,
StepPurchaseQuantity: *sizePrice.EachBoxNum, StepPurchaseQuantity: stepPurchaseQuantity,
IsHighlyCustomized: *cart.IsHighlyCustomized > 0, IsHighlyCustomized: *cart.IsHighlyCustomized > 0,
IsSelected: *cart.IsSelected > 0, IsSelected: *cart.IsSelected > 0,
TemplateTag: templateTag,
Logo: snapShot.Logo,
} }
//是否有失效的 //是否有失效的
if description, ok := mapCartChange[cart.Id]; ok { if description, ok := mapCartChange[cart.Id]; ok {
@ -201,7 +210,7 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
Meta: types.Meta{ Meta: types.Meta{
TotalCount: total, TotalCount: total,
PageCount: int64(math.Ceil(float64(total) / float64(limit))), PageCount: int64(math.Ceil(float64(total) / float64(limit))),
CurrentPage: req.CurrentPage, CurrentPage: currentPage,
PerPage: limit, PerPage: limit,
}, },
CartList: list, CartList: list,
@ -214,7 +223,6 @@ type GetRelationInfoReq struct {
MapSize map[int64]gmodel.FsProductSize MapSize map[int64]gmodel.FsProductSize
MapModel map[int64]gmodel.FsProductModel3d MapModel map[int64]gmodel.FsProductModel3d
MapTemplate map[int64]gmodel.FsProductTemplateV2 MapTemplate map[int64]gmodel.FsProductTemplateV2
MapSizePrice map[string]gmodel.FsProductPrice
MapProduct map[int64]gmodel.FsProduct MapProduct map[int64]gmodel.FsProduct
MapResourceMetadata map[string]interface{} MapResourceMetadata map[string]interface{}
} }
@ -282,15 +290,6 @@ func (l *GetCartsLogic) GetRelationInfo(req GetRelationInfoReq) error {
for _, v := range templateList { for _, v := range templateList {
req.MapTemplate[v.Id] = v req.MapTemplate[v.Id] = v
} }
//根据sizeid获取价格列表
priceList, err := l.svcCtx.AllModels.FsProductPrice.GetPriceListByProductIdsSizeIds(l.ctx, productIds, sizeIds)
if err != nil {
logx.Error(err)
return errors.New("failed to get cart`s product price list")
}
for _, v := range priceList {
req.MapSizePrice[fmt.Sprintf("%d_%d", *v.ProductId, *v.SizeId)] = v
}
return nil return nil
} }

View File

@ -16,6 +16,7 @@ type ServiceContext struct {
AllModels *gmodel.AllModelsGen AllModels *gmodel.AllModelsGen
RabbitMq *initalize.RabbitMqHandle RabbitMq *initalize.RabbitMqHandle
Repositories *initalize.Repositories Repositories *initalize.Repositories
AwsSession *session.Session
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
@ -28,6 +29,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
MysqlConn: conn, MysqlConn: conn,
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)), AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
RabbitMq: initalize.InitRabbitMq(c.SourceRabbitMq, nil), RabbitMq: initalize.InitRabbitMq(c.SourceRabbitMq, nil),
AwsSession: session.Must(session.NewSession(&config)),
Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{ Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: conn, GormDB: conn,
BLMServiceUrl: &c.BLMService.Url, BLMServiceUrl: &c.BLMService.Url,

View File

@ -30,7 +30,7 @@ type DeleteCartReq struct {
} }
type GetCartsReq struct { type GetCartsReq struct {
CurrentPage int `form:"current_page"` //当前页 CartId int64 `form:"cart_id,optional"` //购物车ids可选
} }
type GetCartsRsp struct { type GetCartsRsp struct {
@ -53,6 +53,8 @@ type CartItem struct {
IsInvalid bool `json:"is_invalid"` //是否无效 IsInvalid bool `json:"is_invalid"` //是否无效
InvalidDescription string `json:"invalid_description"` //无效原因 InvalidDescription string `json:"invalid_description"` //无效原因
IsSelected bool `json:"is_selected"` //是否选中 IsSelected bool `json:"is_selected"` //是否选中
TemplateTag string `json:"template_tag"` //模板标签
Logo string `json:"logo"`
} }
type ProductInfo struct { type ProductInfo struct {

View File

@ -67,9 +67,9 @@ var (
//websocket连接存储 //websocket连接存储
mapConnPool = sync.Map{} mapConnPool = sync.Map{}
//每个websocket连接入口缓冲队列长度默认值 //每个websocket连接入口缓冲队列长度默认值
websocketInChanLen = 500 websocketInChanLen = 2000
//每个websocket连接出口缓冲队列长度默认值 //每个websocket连接出口缓冲队列长度默认值
websocketOutChanLen = 500 websocketOutChanLen = 2000
//是否开启debug //是否开启debug
openDebug = true openDebug = true
//允许跨域的origin //允许跨域的origin
@ -192,7 +192,7 @@ func (l *DataTransferLogic) setConnPool(conn *websocket.Conn, userInfo *auth.Use
userId: userInfo.UserId, userId: userInfo.UserId,
guestId: userInfo.GuestId, guestId: userInfo.GuestId,
extendRenderProperty: extendRenderProperty{ extendRenderProperty: extendRenderProperty{
renderChan: make(chan []byte, renderChanLen), renderChan: make(chan websocket_data.RenderImageReqMsg, renderChanLen),
}, },
} }
//保存连接 //保存连接

View File

@ -22,6 +22,8 @@ import (
var ( var (
//每个websocket渲染任务缓冲队列长度默认值 //每个websocket渲染任务缓冲队列长度默认值
renderChanLen = 500 renderChanLen = 500
//每个websocket渲染并发数
renderChanConcurrency = 500
) )
// 渲染处理器 // 渲染处理器
@ -30,16 +32,25 @@ type renderProcessor struct {
// 云渲染属性 // 云渲染属性
type extendRenderProperty struct { type extendRenderProperty struct {
renderChan chan []byte //渲染消息入口的缓冲队列 renderChan chan websocket_data.RenderImageReqMsg //渲染消息入口的缓冲队列
} }
// 处理分发到这里的数据 // 处理分发到这里的数据
func (r *renderProcessor) allocationMessage(w *wsConnectItem, data []byte) { func (r *renderProcessor) allocationMessage(w *wsConnectItem, data []byte) {
//logx.Info("开始处理渲染任务消息:", string(data)) logx.Info("收到渲染任务消息")
var renderImageData websocket_data.RenderImageReqMsg
if err := json.Unmarshal(data, &renderImageData); err != nil {
w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "数据格式错误", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0)
logx.Error("invalid format of websocket render image message", err)
return
}
select { select {
case <-w.closeChan: //已经关闭 case <-w.closeChan: //已经关闭
return return
case w.extendRenderProperty.renderChan <- data: //发入到缓冲队列 case w.extendRenderProperty.renderChan <- renderImageData: //发入到缓冲队列
return
case <-time.After(time.Millisecond * 50): //超过50毫秒丢弃
w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "渲染队列溢出,请稍后再发", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0)
return return
} }
} }
@ -48,29 +59,37 @@ func (r *renderProcessor) allocationMessage(w *wsConnectItem, data []byte) {
func (w *wsConnectItem) consumeRenderImageData() { func (w *wsConnectItem) consumeRenderImageData() {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
logx.Error("func renderImage err:", err) logx.Error("func consumeRenderImageData panic:", err)
} }
}() }()
var data []byte //限制并发
limitChan := make(chan struct{}, renderChanConcurrency)
defer close(limitChan)
for { for {
select { select {
case <-w.closeChan: //已关闭 case <-w.closeChan: //已关闭
return return
case data = <-w.extendRenderProperty.renderChan: //消费数据 case data := <-w.extendRenderProperty.renderChan: //消费数据
w.renderImage(data) logx.Info("准备执行任务。。。。。")
limitChan <- struct{}{}
logx.Info("执行任务中。。。。。")
go func(d websocket_data.RenderImageReqMsg) {
defer func() {
if err := recover(); err != nil {
logx.Error("func renderImage panic:", err)
}
}()
defer func() {
<-limitChan
}()
w.renderImage(d)
}(data)
} }
} }
} }
// 执行渲染任务 // 执行渲染任务
func (w *wsConnectItem) renderImage(data []byte) { func (w *wsConnectItem) renderImage(renderImageData websocket_data.RenderImageReqMsg) {
//logx.Info("消费渲染数据:", string(data))
var renderImageData websocket_data.RenderImageReqMsg
if err := json.Unmarshal(data, &renderImageData); err != nil {
w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "数据格式错误", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0)
logx.Error("invalid format of websocket render image message", err)
return
}
if renderImageData.RenderData.Logo == "" { if renderImageData.RenderData.Logo == "" {
w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "请传入logo", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0) w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "请传入logo", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0)
return return
@ -188,6 +207,7 @@ func (w *wsConnectItem) renderImage(data []byte) {
logx.Error("failed to find render resource:", err) logx.Error("failed to find render resource:", err)
return return
} }
logx.Info("无缓存的渲染图需要unity")
} else { } else {
//返回给客户端 //返回给客户端
w.sendRenderResultData(websocket_data.RenderImageRspMsg{ w.sendRenderResultData(websocket_data.RenderImageRspMsg{

View File

@ -12,10 +12,71 @@ import "basic.api"
service info { service info {
@handler InfoHandler @handler InfoHandler
post /api/info/user(UserInfoRequest) returns (response); post /api/info/user(UserInfoRequest) returns (response);
@handler UserGetProfileHandler
post /api/info/user/profile(QueryProfileRequest) returns (response);
@handler UpdateProfileBaseHandler
post /api/info/user/profile/base/update(ProfileBaseRequest) returns (response);
@handler AddressDefaultHandler
post /api/info/address/default(AddressIdRequest) returns (response);
@handler AddressAddHandler
post /api/info/address/add(AddressRequest) returns (response);
@handler AddressUpdateHandler
post /api/info/address/update(AddressRequest) returns (response);
@handler AddressDeleteHandler
post /api/info/address/delete(AddressIdRequest) returns (response);
@handler AddressListHandler
get /api/info/address/list(request) returns (response);
} }
type ( type (
UserInfoRequest { UserInfoRequest {
Module []string `json:"module"` Module []string `json:"module"`
} }
AddressObjectRequest {
AddressId int64 `json:"address_id"` // 地址id
AddressName string `json:"address_name"` // 地址
}
AddressIdRequest {
AddressId int64 `json:"address_id"` // 地址id
}
AddressNameRequest {
AddressName string `json:"address_name"` // 地址
}
AddressRequest {
AddressId int64 `json:"address_id,optional"`
IsDefault int64 `json:"is_default"` //是否默认
AddressName string `json:"address_name"` //收货人
FirstName string `json:"first_name"` //first_name
LastName string `json:"last_name"` //last_name
Mobile string `json:"mobile"` //手机
ZipCode string `json:"zip_code"` //邮编
Street string `json:"street"` //街道
Suite string `json:"suite"` //房号
City string `json:"city"` //城市
State string `json:"state"` //州
}
ProfileBaseRequest {
FirstName *string `json:"first_name,optional,omitempty"` // 首名
LastName *string `json:"last_name,optional,omitempty"` // 后名
UserName *string `json:"user_name,optional,omitempty"` // 用户名
Mobile *string `json:"mobile,optional,omitempty"` // 电话
Resetaurant *string `json:"resetaurant,optional,omitempty"` // 不知道干什么
Company *string `json:"company,optional,omitempty"` // 公司
}
QueryProfileRequest {
TopKey string `json:"top_key"` // 首名
}
) )

View File

@ -34,7 +34,7 @@ type OrderDetailReq {
type CreateOrderReq { type CreateOrderReq {
CartIds []int64 `json:"cart_ids"` CartIds []int64 `json:"cart_ids"`
DeliveryMethod int64 `json:"delivery_method,options=[1,2]"` // DeliveryMethod int64 `json:"delivery_method,optional,options=[1,2],default=2"`
} }
type CreatePrePaymentByDepositReq { type CreatePrePaymentByDepositReq {

View File

@ -11,9 +11,6 @@ import "basic.api"
service pay { service pay {
@handler OrderPaymentIntentHandler
post /api/pay/payment-intent(OrderPaymentIntentReq) returns (response);
@handler OrderRefundHandler @handler OrderRefundHandler
post /api/pay/refund(OrderRefundReq) returns (response); post /api/pay/refund(OrderRefundReq) returns (response);
@ -28,20 +25,6 @@ type (
OrderRefundRes struct{} OrderRefundRes struct{}
) )
// 生成预付款
type (
OrderPaymentIntentReq {
Sn string `form:"sn"` //订单编号
DeliveryMethod int64 `form:"delivery_method"` //发货方式
AddressId int64 `form:"address_id"` //地址id
PayMethod int64 `form:"pay_method"` //支付方式
}
OrderPaymentIntentRes {
RedirectUrl string `json:"redirect_url"`
ClientSecret string `json:"clientSecret"`
}
)
// StripeWebhook支付通知 // StripeWebhook支付通知
type ( type (
StripeWebhookReq { StripeWebhookReq {

View File

@ -44,9 +44,15 @@ service product {
//获取产品模型信息 //获取产品模型信息
@handler GetModelByPidHandler @handler GetModelByPidHandler
get /api/product/get_model_by_pid(GetModelByPidReq) returns (response); get /api/product/get_model_by_pid(GetModelByPidReq) returns (response);
//获取产品阶梯价格列表 //获取产品阶梯价格列表(即将废弃)
@handler GetPriceByPidHandler @handler GetPriceByPidHandler
get /api/product/get_price_by_pid(GetPriceByPidReq) returns (response); get /api/product/get_price_by_pid(GetPriceByPidReq) returns (response);
//获取产品阶梯价格信息
@handler GetProductStepPriceHandler
get /api/product/get_product_step_price(GetProductStepPriceReq) returns (response);
//根据产品+配件搭配计算价格
@handler CalculateProductPriceHandler
post /api/product/calculate_product_price(CalculateProductPriceReq) returns (response);
//获取产品尺寸列表 //获取产品尺寸列表
@handler GetSizeByPidHandler @handler GetSizeByPidHandler
get /api/product/get_size_by_pid(GetSizeByPidReq) returns (response); get /api/product/get_size_by_pid(GetSizeByPidReq) returns (response);
@ -376,6 +382,22 @@ type PriceItem {
TotalNum int64 `json:"total_num"` TotalNum int64 `json:"total_num"`
Price int64 `json:"price"` Price int64 `json:"price"`
} }
//获取产品阶梯价格信息
type GetProductStepPriceReq {
ProductId int64 `form:"product_id"`
}
//根据产品+配件搭配计算价格
type CalculateProductPriceReq {
ProductId int64 `json:"product_id"`
SizeId int64 `json:"size_id"`
FittingId int64 `json:"fitting_id,optional"`
PurchaseQuantity int64 `json:"purchase_quantity"`
}
type CalculateProductPriceRsp {
ItemPrice string `json:"item_price"`
TotalPrice string `json:"total_price"`
PurchaseQuantity int64 `json:"purchase_quantity"`
}
//获取产品尺寸列表 //获取产品尺寸列表
type GetSizeByPidReq { type GetSizeByPidReq {
Pid string `form:"pid"` Pid string `form:"pid"`

View File

@ -49,7 +49,7 @@ type DeleteCartReq {
//获取购物车列表 //获取购物车列表
type GetCartsReq { type GetCartsReq {
CurrentPage int `form:"current_page"` //当前页 CartId int64 `form:"cart_id,optional"` //购物车ids可选
} }
type GetCartsRsp { type GetCartsRsp {
Meta Meta `json:"meta"` //分页信息 Meta Meta `json:"meta"` //分页信息
@ -70,6 +70,8 @@ type CartItem {
IsInvalid bool `json:"is_invalid"` //是否无效 IsInvalid bool `json:"is_invalid"` //是否无效
InvalidDescription string `json:"invalid_description"` //无效原因 InvalidDescription string `json:"invalid_description"` //无效原因
IsSelected bool `json:"is_selected"` //是否选中 IsSelected bool `json:"is_selected"` //是否选中
TemplateTag string `json:"template_tag"` //模板标签
Logo string `json:"logo"`
} }
type ProductInfo { type ProductInfo {
ProductId int64 `json:"product_id"` //产品id ProductId int64 `json:"product_id"` //产品id

View File

@ -318,6 +318,7 @@ func (l *defaultImageHandle) LogoCombine(ctx context.Context, in *LogoCombineReq
err = curl.NewClient(ctx, &curl.Config{ err = curl.NewClient(ctx, &curl.Config{
BaseUrl: *l.BLMServiceUrl, BaseUrl: *l.BLMServiceUrl,
Url: constants.BLMServiceUrlLogoCombine, Url: constants.BLMServiceUrlLogoCombine,
RequireTimeout: time.Second * 15,
}).PostJson(postMap, &resultBLM) }).PostJson(postMap, &resultBLM)
logc.Infof(ctx, "合图--算法请求--合图--结束时间:%v", time.Now().UTC()) logc.Infof(ctx, "合图--算法请求--合图--结束时间:%v", time.Now().UTC())

View File

@ -15,6 +15,8 @@ import (
"time" "time"
"github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/aws/session"
"github.com/stripe/stripe-go/v75"
"github.com/zeromicro/go-zero/core/logc"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -34,10 +36,22 @@ type (
Create(ctx context.Context, in *CreateReq) (res *CreateRes, err error) Create(ctx context.Context, in *CreateReq) (res *CreateRes, err error)
// 预支付--定金 // 预支付--定金
CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error) CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error)
// 预支付--定金
CreatePrePaymentByBalance(ctx context.Context, in *CreatePrePaymentByBalanceReq) (res *CreatePrePaymentByBalanceRes, err error)
// 列表 // 列表
List(ctx context.Context, in *ListReq) (res *ListRes, err error) List(ctx context.Context, in *ListReq) (res *ListRes, err error)
// 详情 // 详情
Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error) Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error)
// 支付成功
PaymentSuccessful(ctx context.Context, in *PaymentSuccessfulReq) (res *PaymentSuccessfulRes, err error)
}
PayInfo struct {
PayMethod string `json:"pay_method"` // 交易方式
PayTime time.Time `json:"pay_time"` // 支付时间
Status gmodel.PayStatus `json:"status"` // 当前状态
StatusLink []gmodel.PayStatus `json:"status_link"` // 状态链路
TradeNo string `json:"trade_no"` // 支付交易号
} }
OrderAddress struct { OrderAddress struct {
@ -61,6 +75,16 @@ type (
Amount int64 `json:"amount"` // 金额 Amount int64 `json:"amount"` // 金额
Label string `json:"label"` // 标签 Label string `json:"label"` // 标签
} }
/* 支付成功 */
PaymentSuccessfulReq struct {
EventId string
PaymentMethod string
Charge *stripe.Charge
}
PaymentSuccessfulRes struct{}
/* 支付成功 */
/* 预支付--定金 */ /* 预支付--定金 */
CreatePrePaymentByDepositReq struct { CreatePrePaymentByDepositReq struct {
StripeKey string `json:"stripe_key"` StripeKey string `json:"stripe_key"`
@ -69,7 +93,7 @@ type (
UserId int64 `json:"user_id"` UserId int64 `json:"user_id"`
OrderSn string `json:"order_sn"` OrderSn string `json:"order_sn"`
DeliveryMethod int64 `json:"delivery_method"` DeliveryMethod int64 `json:"delivery_method"`
DeliveryAddress *OrderAddress `json:"delivery_address"` // 收货地址 DeliveryAddress *OrderAddress `json:"delivery_address"`
} }
CreatePrePaymentByDepositRes struct { CreatePrePaymentByDepositRes struct {
ErrorCode basic.StatusResponse ErrorCode basic.StatusResponse
@ -78,6 +102,21 @@ type (
} }
/* 预支付--定金 */ /* 预支付--定金 */
/* 预支付--尾款 */
CreatePrePaymentByBalanceReq struct {
StripeKey string `json:"stripe_key"`
Currency string `json:"currency"`
Country string `json:"country"`
UserId int64 `json:"user_id"`
OrderSn string `json:"order_sn"`
}
CreatePrePaymentByBalanceRes struct {
ErrorCode basic.StatusResponse
OrderDetail gmodel.OrderDetail
OrderPay OrderPay
}
/* 预支付--尾款 */
/* 下单 */ /* 下单 */
CreateReq struct { CreateReq struct {
ExpectedDeliveryTime time.Time `json:"expected_delivery_time"` // 预计到货时间 ExpectedDeliveryTime time.Time `json:"expected_delivery_time"` // 预计到货时间
@ -122,6 +161,312 @@ type (
/* 列表 */ /* 列表 */
) )
// 支付成功
func (d *defaultOrder) PaymentSuccessful(ctx context.Context, in *PaymentSuccessfulReq) (res *PaymentSuccessfulRes, err error) {
var orderSn string
var payStage string
var ok bool
var card string
var brand string
var country string
var currency string
var tradeSn string
var payAmount int64
var payTitle string
var payTime time.Time
var paymentMethod int64 = 1
if in.PaymentMethod == "stripe" {
paymentMethod = 1
}
if in.PaymentMethod == "paypal" {
paymentMethod = 2
}
if in.Charge != nil {
charge := in.Charge
orderSn, ok = charge.Metadata["order_sn"]
if !ok || orderSn == "" {
err = errors.New("order_sn is empty")
logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err)
return &PaymentSuccessfulRes{}, err
}
payStage, ok = charge.Metadata["pay_stage"]
if !ok || payStage == "" {
err = errors.New("pay_stage is empty")
logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err)
return &PaymentSuccessfulRes{}, err
}
country, ok = charge.Metadata["country"]
if !ok || country == "" {
err = errors.New("country is empty")
logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err)
return &PaymentSuccessfulRes{}, err
}
if charge.PaymentMethodDetails != nil {
if charge.PaymentMethodDetails.Card != nil {
if charge.PaymentMethodDetails.Card.Last4 != "" {
card = charge.PaymentMethodDetails.Card.Last4
}
if charge.PaymentMethodDetails.Card.Brand != "" {
brand = string(charge.PaymentMethodDetails.Card.Brand)
}
}
}
if charge.Currency != "" {
currency = string(charge.Currency)
}
tradeSn = charge.ID
payAmount = charge.Amount
payTitle = charge.Description
payTime = time.Unix(charge.Created, 0).UTC()
}
err = d.MysqlConn.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var orderInfo gmodel.FsOrder
result := tx.Where("is_del = ?", 0).Where("order_sn = ?", orderSn).Take(&orderInfo)
err = result.Error
if err != nil {
logx.Errorf("PaymentSuccessful failed order Take, eventId:%s,err: %v", in.EventId, err)
return err
}
ress, err := d.OrderDetailHandler(ctx, &orderInfo, 0)
if err != nil {
logx.Errorf("PaymentSuccessful failed DetailOrderDetailHandler,eventId:%s, err: %v", in.EventId, err)
return err
}
var ntime = time.Now().UTC()
if (payStage == "deposit" && *orderInfo.PayStatus == int64(constants.ORDERPAYSTATUSUNPAIDDEPOSIT)) || (payStage == "remaining_balance" && *orderInfo.PayStatus == int64(constants.ORDERPAYSTATUSPAIDDEPOSIT)) {
var payStatus = int64(constants.PAYSTATUSPAID)
var payStageInt int64
var orderPayStatusCode constants.OrderPayStatusCode
// 订单状态--当前
var status gmodel.OrderStatus
var statusLink []gmodel.OrderStatus
var uOrderDetail = make(map[string]interface{})
var payInfo PayInfo
payInfo.PayMethod = in.PaymentMethod
payInfo.PayTime = payTime
payInfo.TradeNo = tradeSn
// 当前状态
var statusCode constants.OrderStatusCode
var statusCodePre constants.OrderStatusCode
if payStage == "deposit" {
if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL {
// 直邮
statusCode = constants.ORDER_STATUS_DIRECTMAIL_ORDERED
}
if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDSCLOUDSTORE {
// 云仓
statusCode = constants.ORDER_STATUS_CLOUDSTORE_ORDERED
}
payStageInt = 1
orderPayStatusCode = constants.ORDERPAYSTATUSPAIDDEPOSIT
status = gmodel.OrderStatus{
Ctime: &ntime,
Utime: &ntime,
StatusCode: statusCode,
StatusTitle: constants.OrderStatusMessage[statusCode],
}
statusLink = order.UpdateOrderStatusLink(ress.OrderDetailOriginal.OrderInfo.StatusLink, gmodel.OrderStatus{
Ctime: &ntime,
Utime: &ntime,
StatusCode: statusCode,
StatusTitle: constants.OrderStatusMessage[statusCode],
})
payInfo.Status = gmodel.PayStatus{
StatusCode: int64(constants.PAYSTATUSPAID),
StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSPAID],
}
payInfo.StatusLink = append(ress.OrderDetail.OrderAmount.Deposit.StatusLink, payInfo.Status)
uOrderDetail["order_amount"] = struct {
Deposit PayInfo `json:"deposit"`
}{
Deposit: payInfo,
}
}
if payStage == "remaining_balance" {
if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL {
// 直邮
statusCodePre = constants.ORDER_STATUS_DIRECTMAIL_ORDERED
statusCode = constants.ORDER_STATUS_DIRECTMAIL_ORDEREDMAINING
}
if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDSCLOUDSTORE {
// 云仓
statusCodePre = constants.ORDER_STATUS_CLOUDSTORE_ORDERED
statusCode = constants.ORDER_STATUS_CLOUDSTORE_ORDEREDMAINING
}
payStageInt = 2
orderPayStatusCode = constants.ORDERPAYSTATUSPAIDDREMAINING
var statusChildren []*gmodel.OrderStatus
// 更新订单状态链路--子状态
for oStatusLinkKey, oStatusLink := range ress.OrderDetail.OrderInfo.StatusLink {
if oStatusLink.StatusCode == statusCodePre {
statusChildren = append(oStatusLink.Children, &gmodel.OrderStatus{
Ctime: &ntime,
Utime: &ntime,
StatusCode: statusCode,
StatusTitle: constants.OrderStatusMessage[statusCode],
})
ress.OrderDetail.OrderInfo.StatusLink[oStatusLinkKey].Children = statusChildren
}
}
statusLink = ress.OrderDetail.OrderInfo.StatusLink
if ress.OrderDetail.OrderInfo.Status.StatusCode == constants.ORDER_STATUS_DIRECTMAIL_ORDERED || ress.OrderDetail.OrderInfo.Status.StatusCode == constants.ORDER_STATUS_CLOUDSTORE_ORDERED {
status = ress.OrderDetail.OrderInfo.Status
status.Children = statusChildren
}
payInfo.Status = gmodel.PayStatus{
StatusCode: int64(constants.PAYSTATUSPAID),
StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSPAID],
}
payInfo.StatusLink = append(ress.OrderDetail.OrderAmount.RemainingBalance.StatusLink, payInfo.Status)
uOrderDetail["order_amount"] = struct {
RemainingBalance PayInfo `json:"remaining_balance"`
}{
RemainingBalance: payInfo,
}
}
// 新增交易信息
tx.Create(&gmodel.FsOrderTrade{
UserId: orderInfo.UserId,
OrderSn: &orderSn,
OrderSource: orderInfo.OrderSource,
TradeSn: &tradeSn,
PayAmount: &payAmount,
PayStatus: &payStatus,
PaymentMethod: &paymentMethod,
PayStage: &payStageInt,
CardSn: &card,
CardBrand: &brand,
Country: &country,
Currency: &currency,
Ctime: &ntime,
Utime: &ntime,
PayTitle: &payTitle,
})
var sql string
if *orderInfo.Status == int64(constants.ORDER_STATUS_UNPAIDDEPOSIT) {
sql = fmt.Sprintf(", `utime` = '%s', `pay_status` = %d, `status` = %d ", ntime, orderPayStatusCode, statusCode)
} else {
sql = fmt.Sprintf(", `utime` = '%s', `pay_status` = %d", ntime, orderPayStatusCode)
}
// 更新订单信息
uOrderDetail["pay_status"] = orderPayStatusCode
uOrderDetail["order_info"] = struct {
Utime *time.Time `json:"utime"`
Status gmodel.OrderStatus `json:"status"`
StatusLink []gmodel.OrderStatus `json:"status_link"`
}{
Utime: &ntime,
Status: status,
StatusLink: statusLink,
}
fmt.Printf("uOrderDetail :%+v", uOrderDetail)
if len(uOrderDetail) > 0 {
err = fssql.MetadataOrderPATCH(d.MysqlConn, sql, orderSn, gmodel.FsOrder{}, uOrderDetail, "id = ?", orderInfo.Id)
if err != nil {
logx.Errorf("PaymentSuccessful failed MetadataOrderPATCH,eventId:%s, err: %v", in.EventId, err)
return err
}
}
}
return nil
})
return &PaymentSuccessfulRes{}, nil
}
// 预支付--尾款
func (d *defaultOrder) CreatePrePaymentByBalance(ctx context.Context, in *CreatePrePaymentByBalanceReq) (res *CreatePrePaymentByBalanceRes, err error) {
var errorCode basic.StatusResponse
var order gmodel.FsOrder
model := d.MysqlConn.Where("is_del = ?", 0)
if in.UserId != 0 {
model.Where("user_id = ?", in.UserId)
}
if in.OrderSn != "" {
model.Where("order_sn = ?", in.OrderSn)
}
result := model.Take(&order)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
} else {
errorCode = *basic.CodeServiceErr
}
logx.Errorf("create prePayment balance failed, err: %v", err)
return &CreatePrePaymentByBalanceRes{
ErrorCode: errorCode,
}, result.Error
}
// 非未支付
if *order.PayStatus != int64(constants.ORDERPAYSTATUSPAIDDEPOSIT) {
errorCode = *basic.CodeErrOrderCreatePrePaymentNoUnPaid
err = errors.New("order balance pay status is not unPaid")
logx.Errorf("create prePayment balance failed, err: %v", err)
return &CreatePrePaymentByBalanceRes{
ErrorCode: errorCode,
}, err
}
ress, err := d.OrderDetailHandler(ctx, &order, 1)
if err != nil {
logx.Errorf("create prePayment balance failed DetailOrderDetailHandler, err: %v", err)
errorCode = *basic.CodeServiceErr
return &CreatePrePaymentByBalanceRes{
ErrorCode: errorCode,
}, err
}
// 支付初始化
amount := int64(ress.OrderDetailOriginal.OrderAmount.RemainingBalance.PayAmount.Current.CurrentAmount.(float64) / float64(10))
payConfig := &pay.Config{}
payConfig.Stripe.PayType = "intent"
payConfig.Stripe.Key = in.StripeKey
var metadata = make(map[string]string, 2)
metadata["model"] = "product_order"
metadata["order_sn"] = in.OrderSn
metadata["pay_stage"] = "remaining_balance"
metadata["country"] = in.Country
var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
Metadata: metadata,
ProductName: "支付尾款后期统一调整",
Amount: amount,
Currency: "usd",
Quantity: 1,
ProductDescription: "支付尾款后期统一调整",
}
payDriver := pay.NewPayDriver(1, payConfig)
prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
if err != nil {
logx.Errorf("create prePayment balance failed GeneratePrepayment, err: %v", err)
errorCode = *basic.CodeServiceErr
return &CreatePrePaymentByBalanceRes{
ErrorCode: errorCode,
}, nil
}
return &CreatePrePaymentByBalanceRes{
OrderDetail: ress.OrderDetail,
OrderPay: OrderPay{
ClientSecret: prepaymentRes.ClientSecret,
Country: in.Country,
Currency: in.Currency,
Method: payConfig.Stripe.PayType,
OrderSn: in.OrderSn,
PayStage: 2,
Total: OrderPayTotal{
Amount: amount,
Label: "支付尾款后期统一调整",
},
},
}, nil
}
// 预支付--定金 // 预支付--定金
func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error) { func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error) {
var errorCode basic.StatusResponse var errorCode basic.StatusResponse
@ -148,7 +493,7 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
// 非未支付 // 非未支付
if *order.PayStatus != int64(constants.ORDERPAYSTATUSUNPAIDDEPOSIT) { if *order.PayStatus != int64(constants.ORDERPAYSTATUSUNPAIDDEPOSIT) {
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound errorCode = *basic.CodeErrOrderCreatePrePaymentNoUnPaid
err = errors.New("order pay status is not unPaidDeposit") err = errors.New("order pay status is not unPaidDeposit")
logx.Errorf("create prePayment deposit failed, err: %v", err) logx.Errorf("create prePayment deposit failed, err: %v", err)
return &CreatePrePaymentByDepositRes{ return &CreatePrePaymentByDepositRes{
@ -161,6 +506,8 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
ctime := *order.Ctime ctime := *order.Ctime
ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix() ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix()
ntimeTimeOut := ntime.Unix() ntimeTimeOut := ntime.Unix()
// 测试超时支付不限制
if ctimeTimeOut == ntimeTimeOut { if ctimeTimeOut == ntimeTimeOut {
errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout
err = errors.New("order pay timeout") err = errors.New("order pay timeout")
@ -170,7 +517,7 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
}, err }, err
} }
ress, err := d.OrderDetailHandler(ctx, &order) ress, err := d.OrderDetailHandler(ctx, &order, 0)
if err != nil { if err != nil {
logx.Errorf("create prePayment deposit failed DetailOrderDetailHandler, err: %v", err) logx.Errorf("create prePayment deposit failed DetailOrderDetailHandler, err: %v", err)
errorCode = *basic.CodeServiceErr errorCode = *basic.CodeServiceErr
@ -182,15 +529,13 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
var uOrderDetail = make(map[string]interface{}) var uOrderDetail = make(map[string]interface{})
var orderAddress *gmodel.OrderAddress var orderAddress *gmodel.OrderAddress
if in.DeliveryAddress != nil { if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL {
if in.DeliveryAddress.Name != ress.OrderDetailOriginal.DeliveryAddress.Name || in.DeliveryAddress.Address != ress.OrderDetail.DeliveryAddress.Address || in.DeliveryAddress.Mobile != ress.OrderDetail.DeliveryAddress.Mobile {
orderAddress = &gmodel.OrderAddress{ orderAddress = &gmodel.OrderAddress{
Name: in.DeliveryAddress.Name, Name: in.DeliveryAddress.Name,
Mobile: in.DeliveryAddress.Mobile, Mobile: in.DeliveryAddress.Mobile,
Address: in.DeliveryAddress.Address, Address: in.DeliveryAddress.Address,
} }
} }
}
var sql string = fmt.Sprintf(", `utime` = '%s'", ntime) var sql string = fmt.Sprintf(", `utime` = '%s'", ntime)
// 是否更新 // 是否更新
@ -223,31 +568,7 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
} }
} }
} }
// 支付初始化
amount := int64(ress.OrderDetailOriginal.OrderAmount.Deposit.PayAmount.Current.CurrentAmount.(float64) / float64(10))
payConfig := &pay.Config{}
payConfig.Stripe.PayType = "intent"
payConfig.Stripe.Key = in.StripeKey
var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
OrderSn: in.OrderSn,
ProductName: "支付标题",
Amount: amount,
Currency: "usd",
Quantity: 1,
ProductDescription: "支付描述",
}
payDriver := pay.NewPayDriver(1, payConfig)
prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
if err != nil {
logx.Errorf("create prePayment deposit failed GeneratePrepayment, err: %v", err)
errorCode = *basic.CodeServiceErr
return &CreatePrePaymentByDepositRes{
ErrorCode: errorCode,
}, nil
} else {
//uOrderDetail["order_amount"] = map[type]type
}
if len(uOrderDetail) > 0 { if len(uOrderDetail) > 0 {
err = fssql.MetadataOrderPATCH(d.MysqlConn, sql, in.OrderSn, gmodel.FsOrder{}, uOrderDetail, "id = ?", order.Id) err = fssql.MetadataOrderPATCH(d.MysqlConn, sql, in.OrderSn, gmodel.FsOrder{}, uOrderDetail, "id = ?", order.Id)
if err != nil { if err != nil {
@ -263,6 +584,34 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
ress.OrderDetail.OrderInfo.DeliveryMethod = in.DeliveryMethod ress.OrderDetail.OrderInfo.DeliveryMethod = in.DeliveryMethod
ress.OrderDetail.DeliveryAddress = orderAddress ress.OrderDetail.DeliveryAddress = orderAddress
// 支付初始化
amount := int64(ress.OrderDetailOriginal.OrderAmount.Deposit.PayAmount.Current.CurrentAmount.(float64) / float64(10))
payConfig := &pay.Config{}
payConfig.Stripe.PayType = "intent"
payConfig.Stripe.Key = in.StripeKey
var metadata = make(map[string]string, 2)
metadata["model"] = "product_order"
metadata["order_sn"] = in.OrderSn
metadata["pay_stage"] = "deposit"
metadata["country"] = in.Country
var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
Metadata: metadata,
ProductName: "支付首款",
Amount: amount,
Currency: "usd",
Quantity: 1,
ProductDescription: "支付首款",
}
payDriver := pay.NewPayDriver(1, payConfig)
prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
if err != nil {
logx.Errorf("create prePayment deposit failed GeneratePrepayment, err: %v", err)
errorCode = *basic.CodeServiceErr
return &CreatePrePaymentByDepositRes{
ErrorCode: errorCode,
}, nil
}
return &CreatePrePaymentByDepositRes{ return &CreatePrePaymentByDepositRes{
OrderDetail: ress.OrderDetail, OrderDetail: ress.OrderDetail,
OrderPay: OrderPay{ OrderPay: OrderPay{
@ -320,7 +669,7 @@ func (d *defaultOrder) List(ctx context.Context, in *ListReq) (res *ListRes, err
return nil, result.Error return nil, result.Error
} }
for _, order := range orderList { for _, order := range orderList {
ress, err := d.OrderDetailHandler(ctx, &order) ress, err := d.OrderDetailHandler(ctx, &order, 1)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -365,6 +714,7 @@ func (d *defaultOrder) Detail(ctx context.Context, in *DetailReq) (res *DetailRe
} }
// 是否超时支付 // 是否超时支付
if *order.Status == int64(constants.ORDER_STATUS_UNPAIDDEPOSIT) {
ctime := *order.Ctime ctime := *order.Ctime
ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix() ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix()
ntimeTimeOut := time.Now().UTC().Unix() ntimeTimeOut := time.Now().UTC().Unix()
@ -376,8 +726,9 @@ func (d *defaultOrder) Detail(ctx context.Context, in *DetailReq) (res *DetailRe
ErrorCode: errorCode, ErrorCode: errorCode,
}, err }, err
} }
}
ress, err := d.OrderDetailHandler(ctx, &order) ress, err := d.OrderDetailHandler(ctx, &order, 1)
if err != nil { if err != nil {
logx.Errorf("order detail failed, err: %v", err) logx.Errorf("order detail failed, err: %v", err)
errorCode = *basic.CodeServiceErr errorCode = *basic.CodeServiceErr
@ -403,8 +754,8 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
resShoppingCartFind := tx.Table(gmodel.NewFsShoppingCartModel(tx).TableName()). resShoppingCartFind := tx.Table(gmodel.NewFsShoppingCartModel(tx).TableName()).
Preload("ShoppingCartProduct", func(dbPreload *gorm.DB) *gorm.DB { Preload("ShoppingCartProduct", func(dbPreload *gorm.DB) *gorm.DB {
return dbPreload.Table(gmodel.NewFsProductModel(tx).TableName()).Preload("CoverResource") return dbPreload.Table(gmodel.NewFsProductModel(tx).TableName()).Preload("CoverResource")
}).Preload("ShoppingCartProductPriceList"). }).
Preload("ShoppingCartProductModel3dList"). Preload("ShoppingCartProductModel3d").
Preload("ShoppingCartProductModel3dFitting"). Preload("ShoppingCartProductModel3dFitting").
Where("id IN ?", in.CartIds). Where("id IN ?", in.CartIds).
Where("user_id = ?", in.UserId). Where("user_id = ?", in.UserId).
@ -465,10 +816,6 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
for _, shoppingCart := range shoppingCartList { for _, shoppingCart := range shoppingCartList {
// 购物车快照 // 购物车快照
var shoppingCartSnapshot gmodel.CartSnapshot var shoppingCartSnapshot gmodel.CartSnapshot
// 购物车商品价格
var shoppingCartProductPrice *gmodel.FsProductPrice
// 购物车商品模型
var shoppingCartProductModel3d *gmodel.FsProductModel3d
if shoppingCart.Snapshot != nil { if shoppingCart.Snapshot != nil {
json.Unmarshal([]byte(*shoppingCart.Snapshot), &shoppingCartSnapshot) json.Unmarshal([]byte(*shoppingCart.Snapshot), &shoppingCartSnapshot)
} }
@ -478,69 +825,21 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
errorCode.Message = "create order failed, product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent" errorCode.Message = "create order failed, product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message) return errors.New(errorCode.Message)
} }
// 商品价格异常
if len(shoppingCart.ShoppingCartProductPriceList) == 0 {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message)
} else {
var isProductPrice bool
for _, shoppingCartProductPriceInfo := range shoppingCart.ShoppingCartProductPriceList {
if *shoppingCart.SizeId == *shoppingCartProductPriceInfo.SizeId {
shoppingCartProductPrice = shoppingCartProductPriceInfo
isProductPrice = true
break
}
}
if !isProductPrice {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message)
}
shoppingCart.ShoppingCartProductPriceList = []*gmodel.FsProductPrice{shoppingCartProductPrice}
}
// 商品模型异常 var stepPriceJson gmodel.StepPriceJsonStruct
if len(shoppingCart.ShoppingCartProductModel3dList) == 0 { if shoppingCart.ShoppingCartProductModel3d.StepPrice != nil {
errorCode = *basic.CodeErrOrderCreatProductAccessoryAbsent err = json.Unmarshal(*shoppingCart.ShoppingCartProductModel3d.StepPrice, &stepPriceJson)
errorCode.Message = "create order failed, accessoryof product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent" if err != nil {
return errors.New(errorCode.Message) return err
}
} else { } else {
var isProductModel bool
for _, shoppingCartProductModel3dInfo := range shoppingCart.ShoppingCartProductModel3dList {
if *shoppingCart.SizeId == *shoppingCartProductModel3dInfo.SizeId {
shoppingCartProductModel3d = shoppingCartProductModel3dInfo
isProductModel = true
break
}
}
if !isProductModel {
errorCode = *basic.CodeErrOrderCreatProductAccessoryAbsent
errorCode.Message = "create order failed, accessory of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message)
}
shoppingCart.ShoppingCartProductModel3dList = []*gmodel.FsProductModel3d{shoppingCartProductModel3d}
}
var stepNum []int
var stepPrice []int
if *shoppingCartProductPrice.StepNum == "" {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, step num of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed"
return errors.New(errorCode.Message)
} else {
json.Unmarshal([]byte(*shoppingCartProductPrice.StepNum), &stepNum)
}
if *shoppingCartProductPrice.StepPrice == "" {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed" errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed"
return errors.New(errorCode.Message) return errors.New("shoppingCartProductModel3d.StepPrice nil")
} else {
json.Unmarshal([]byte(*shoppingCartProductPrice.StepPrice), &stepPrice)
} }
/* 计算价格 */ /* 计算价格 */
productPrice, productTotalPrice, stepNum, stepPrice, err := NewShoppingCart(tx, nil, nil).CaculateCartPrice(*shoppingCart.PurchaseQuantity, shoppingCartProductPrice, *shoppingCart.ShoppingCartProductModel3dFitting.Price) productTotalPrice, productPrice, err := NewShoppingCart(tx, nil, nil).CaculateStepPrice(*shoppingCart.PurchaseQuantity, stepPriceJson, *shoppingCart.ShoppingCartProductModel3dFitting.Price)
if err != nil { if err != nil {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed" errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed"
@ -556,7 +855,32 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
if shoppingCart.ShoppingCartProduct.CoverResource != nil && shoppingCart.ShoppingCartProduct.CoverResource.Metadata != nil { if shoppingCart.ShoppingCartProduct.CoverResource != nil && shoppingCart.ShoppingCartProduct.CoverResource.Metadata != nil {
json.Unmarshal(*shoppingCart.ShoppingCartProduct.CoverResource.Metadata, &productCoverMetadata) json.Unmarshal(*shoppingCart.ShoppingCartProduct.CoverResource.Metadata, &productCoverMetadata)
} }
orderProductList = append(orderProductList, gmodel.OrderProduct{ snapshot, err := d.OrderDetailSnapshotHandler(ctx, shoppingCart.FsShoppingCart.Snapshot)
if err != nil {
return err
}
var shoppingCartSnapshotInter = &gmodel.FsShoppingCartData{
Id: shoppingCart.FsShoppingCart.Id,
UserId: shoppingCart.FsShoppingCart.UserId,
ProductId: shoppingCart.FsShoppingCart.ProductId,
TemplateId: shoppingCart.FsShoppingCart.TemplateId,
ModelId: shoppingCart.FsShoppingCart.ModelId,
SizeId: shoppingCart.FsShoppingCart.SizeId,
LightId: shoppingCart.FsShoppingCart.LightId,
FittingId: shoppingCart.FsShoppingCart.FittingId,
PurchaseQuantity: shoppingCart.FsShoppingCart.PurchaseQuantity,
Snapshot: &snapshot,
SnapshotData: shoppingCart.FsShoppingCart.Snapshot,
IsSelected: shoppingCart.FsShoppingCart.IsSelected,
IsHighlyCustomized: shoppingCart.FsShoppingCart.IsHighlyCustomized,
Ctime: shoppingCart.FsShoppingCart.Ctime,
Utime: shoppingCart.FsShoppingCart.Utime,
}
var purchaseQuantityInter = gmodel.PurchaseQuantity{
Current: *shoppingCart.PurchaseQuantity,
Initiate: *shoppingCart.PurchaseQuantity,
}
productInter := gmodel.OrderProduct{
TotalPrice: order.GetAmountInfo(order.GetAmountInfoReq{ TotalPrice: order.GetAmountInfo(order.GetAmountInfoReq{
ExchangeRate: in.ExchangeRate, ExchangeRate: in.ExchangeRate,
Initiate: productTotalPrice, Initiate: productTotalPrice,
@ -565,7 +889,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
OriginalCurrency: in.OriginalCurrency, OriginalCurrency: in.OriginalCurrency,
}), }),
ExpectedDeliveryTime: &in.ExpectedDeliveryTime, ExpectedDeliveryTime: &in.ExpectedDeliveryTime,
PurchaseQuantity: *shoppingCart.PurchaseQuantity, PurchaseQuantity: purchaseQuantityInter,
ProductID: *shoppingCart.ProductId, ProductID: *shoppingCart.ProductId,
ProductCover: *shoppingCart.ShoppingCartProduct.Cover, ProductCover: *shoppingCart.ShoppingCartProduct.Cover,
ProductCoverMetadata: productCoverMetadata, ProductCoverMetadata: productCoverMetadata,
@ -578,7 +902,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
OriginalCurrency: in.OriginalCurrency, OriginalCurrency: in.OriginalCurrency,
}), }),
ProductSnapshot: shoppingCart.ShoppingCartProduct, ProductSnapshot: shoppingCart.ShoppingCartProduct,
ShoppingCartSnapshot: &shoppingCart.FsShoppingCart, ShoppingCartSnapshot: shoppingCartSnapshotInter,
ProductSn: *shoppingCart.ShoppingCartProduct.Sn, ProductSn: *shoppingCart.ShoppingCartProduct.Sn,
DiyInformation: &shoppingCartSnapshot.UserDiyInformation, DiyInformation: &shoppingCartSnapshot.UserDiyInformation,
FittingInfo: &gmodel.OrderProductFittingInfo{ FittingInfo: &gmodel.OrderProductFittingInfo{
@ -593,9 +917,9 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
Cm: shoppingCartSnapshot.SizeInfo.Cm, Cm: shoppingCartSnapshot.SizeInfo.Cm,
}, },
}, },
StepNum: stepNum,
IsHighlyCustomized: *shoppingCart.IsHighlyCustomized, IsHighlyCustomized: *shoppingCart.IsHighlyCustomized,
}) }
orderProductList = append(orderProductList, productInter)
} }
subtotal = order.GetAmountInfo(order.GetAmountInfoReq{ subtotal = order.GetAmountInfo(order.GetAmountInfoReq{
@ -621,6 +945,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
StatusCode: int64(constants.PAYSTATUSUNPAID), StatusCode: int64(constants.PAYSTATUSUNPAID),
StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSUNPAID], StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSUNPAID],
}, },
StatusLink: make([]gmodel.PayStatus, 0),
PayAmount: order.GetAmountInfo(order.GetAmountInfoReq{ PayAmount: order.GetAmountInfo(order.GetAmountInfoReq{
ExchangeRate: in.ExchangeRate, ExchangeRate: in.ExchangeRate,
Initiate: depositInt, Initiate: depositInt,
@ -637,6 +962,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
StatusCode: int64(constants.PAYSTATUSUNPAID), StatusCode: int64(constants.PAYSTATUSUNPAID),
StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSUNPAID], StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSUNPAID],
}, },
StatusLink: make([]gmodel.PayStatus, 0),
PayAmount: order.GetAmountInfo(order.GetAmountInfoReq{ PayAmount: order.GetAmountInfo(order.GetAmountInfoReq{
ExchangeRate: in.ExchangeRate, ExchangeRate: in.ExchangeRate,
Initiate: remainingBalanceInt, Initiate: remainingBalanceInt,
@ -659,8 +985,8 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
var status = gmodel.OrderStatus{ var status = gmodel.OrderStatus{
Ctime: &nowTime, Ctime: &nowTime,
Utime: &nowTime, Utime: &nowTime,
StatusCode: constants.ORDERSTATUSUNPAIDDEPOSIT, StatusCode: constants.ORDER_STATUS_UNPAIDDEPOSIT,
StatusTitle: constants.OrderStatusMessage[constants.ORDERSTATUSUNPAIDDEPOSIT], StatusTitle: constants.OrderStatusMessage[constants.ORDER_STATUS_UNPAIDDEPOSIT],
} }
// 订单状态--链路 // 订单状态--链路
var statusLink = order.GenerateOrderStatusLink(in.DeliveryMethod, nowTime, in.ExpectedDeliveryTime) var statusLink = order.GenerateOrderStatusLink(in.DeliveryMethod, nowTime, in.ExpectedDeliveryTime)
@ -719,8 +1045,68 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
}, nil }, nil
} }
// 处理订单购物车快照
func (d *defaultOrder) OrderDetailSnapshotHandler(ctx context.Context, req *string) (res map[string]interface{}, err error) {
var snapshot map[string]interface{}
json.Unmarshal([]byte(*req), &snapshot)
snapshotFittingInfoData, snapshotFittingInfoEx := snapshot["fitting_info"]
var fittingInfoMap map[string]interface{}
if snapshotFittingInfoEx {
var snapshotFittingInfoJson map[string]interface{}
var fittingName string
snapshotFittingInfo := snapshotFittingInfoData.(map[string]interface{})
snapshotFittingInfoJsonData, snapshotFittingInfoJsonEx := snapshotFittingInfo["fitting_json"]
if snapshotFittingInfoJsonEx {
json.Unmarshal([]byte(snapshotFittingInfoJsonData.(string)), &snapshotFittingInfoJson)
}
fittingNameData, fittingNameEx := snapshotFittingInfo["fitting_name"]
if fittingNameEx {
fittingName = fittingNameData.(string)
}
fittingInfoMap = make(map[string]interface{}, 2)
fittingInfoMap["fitting_json"] = snapshotFittingInfoJson
fittingInfoMap["fitting_name"] = fittingName
}
snapshot["fitting_info"] = fittingInfoMap
snapshotModelInfoData, snapshotModelInfoEx := snapshot["model_info"]
var modelInfoMap map[string]interface{}
if snapshotModelInfoEx {
var snapshotModelInfoJson map[string]interface{}
snapshotModelInfo := snapshotModelInfoData.(map[string]interface{})
snapshotModelInfoJsonData, snapshotModelInfoJsonEx := snapshotModelInfo["model_json"]
if snapshotModelInfoJsonEx {
json.Unmarshal([]byte(snapshotModelInfoJsonData.(string)), &snapshotModelInfoJson)
}
modelInfoMap = make(map[string]interface{}, 1)
modelInfoMap["model_json"] = snapshotModelInfoJson
}
snapshot["model_info"] = modelInfoMap
snapshotTemplateInfoData, snapshotTemplateInfoEx := snapshot["template_info"]
var templateInfoMap map[string]interface{}
if snapshotTemplateInfoEx {
var snapshotTemplateInfoJson map[string]interface{}
var templateTag string
snapshotTemplateInfo := snapshotTemplateInfoData.(map[string]interface{})
snapshotTemplateInfoJsonData, snapshotTemplateInfoJsonEx := snapshotTemplateInfo["template_json"]
if snapshotTemplateInfoJsonEx {
json.Unmarshal([]byte(snapshotTemplateInfoJsonData.(string)), &snapshotTemplateInfoJson)
}
templateTagData, templateTagEx := snapshotTemplateInfo["template_tag"]
if templateTagEx {
templateTag = templateTagData.(string)
}
templateInfoMap = make(map[string]interface{}, 2)
templateInfoMap["template_json"] = snapshotTemplateInfoJson
templateInfoMap["template_tag"] = templateTag
}
snapshot["template_info"] = templateInfoMap
return snapshot, nil
}
// 详情处理 // 详情处理
func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel.FsOrder) (res *DetailRes, err error) { func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel.FsOrder, original int64) (res *DetailRes, err error) {
var orderDetail gmodel.OrderDetail var orderDetail gmodel.OrderDetail
err = json.Unmarshal(*orderInfo.Metadata, &orderDetail) err = json.Unmarshal(*orderInfo.Metadata, &orderDetail)
@ -729,11 +1115,13 @@ func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel
return nil, err return nil, err
} }
orderDetailOriginal := orderDetail orderDetailOriginal := orderDetail
if original == 1 {
for orderProductKey, orderProduct := range orderDetail.OrderProduct { for orderProductKey, orderProduct := range orderDetail.OrderProduct {
orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice) orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice)
orderDetail.OrderProduct[orderProductKey].ItemPrice = order.GetAmountInfoFormat(&orderProduct.ItemPrice) orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice)
orderDetail.OrderProduct[orderProductKey].ShoppingCartSnapshot = nil orderDetail.OrderProduct[orderProductKey].PurchaseQuantity = order.GetPurchaseQuantity(&orderProduct.PurchaseQuantity)
orderDetail.OrderProduct[orderProductKey].ProductSnapshot = nil orderDetail.OrderProduct[orderProductKey].ProductSnapshot = nil
orderDetail.OrderProduct[orderProductKey].ShoppingCartSnapshot.SnapshotData = nil
} }
orderDetail.OrderInfo.StatusLink = order.GetOrderStatusLinkUser(orderDetail.OrderInfo.DeliveryMethod, orderDetail.OrderInfo.StatusLink) orderDetail.OrderInfo.StatusLink = order.GetOrderStatusLinkUser(orderDetail.OrderInfo.DeliveryMethod, orderDetail.OrderInfo.StatusLink)
orderDetail.OrderAmount.Deposit.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Deposit.PayAmount) orderDetail.OrderAmount.Deposit.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Deposit.PayAmount)
@ -741,6 +1129,7 @@ func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel
orderDetail.OrderAmount.Subtotal = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Subtotal) orderDetail.OrderAmount.Subtotal = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Subtotal)
orderDetail.OrderAmount.Total = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Total) orderDetail.OrderAmount.Total = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Total)
orderDetail.PayTimeout = time.Duration(orderDetail.OrderInfo.Ctime.Add(orderDetail.PayTimeout).UTC().Unix() - time.Now().UTC().Unix()) orderDetail.PayTimeout = time.Duration(orderDetail.OrderInfo.Ctime.Add(orderDetail.PayTimeout).UTC().Unix() - time.Now().UTC().Unix())
}
return &DetailRes{ return &DetailRes{
OrderDetail: orderDetail, OrderDetail: orderDetail,

View File

@ -3,15 +3,10 @@ package repositories
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"fusenapi/model/gmodel" "fusenapi/model/gmodel"
"fusenapi/utils/format"
"fusenapi/utils/hash" "fusenapi/utils/hash"
"fusenapi/utils/step_price"
"github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/aws/session"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm" "gorm.io/gorm"
"math"
"strings" "strings"
) )
@ -33,7 +28,7 @@ type (
// 校验订单 // 校验订单
VerifyShoppingCartSnapshotDataChange(req VerifyShoppingCartSnapshotDataChangeReq) error VerifyShoppingCartSnapshotDataChange(req VerifyShoppingCartSnapshotDataChangeReq) error
//计算购物车价格 //计算购物车价格
CaculateCartPrice(purchaseQuantity int64, productPrice *gmodel.FsProductPrice, fittingPrice int64) (ItemPrice, totalPrice int64, stepNum, stepPrice []int, err error) CaculateStepPrice(purchaseQuantity int64, stepPrice gmodel.StepPriceJsonStruct, fittingPrice int64) (totalPrice, itemPrice int64, err error)
} }
) )
@ -132,33 +127,23 @@ func (d *defaultShoppingCart) VerifyShoppingCartSnapshotDataChange(req VerifySho
} }
// 计算价格 // 计算价格
func (d *defaultShoppingCart) CaculateCartPrice(purchaseQuantity int64, productPrice *gmodel.FsProductPrice, fittingPrice int64) (ItemPrice, totalPrice int64, stepNum, stepPrice []int, err error) { func (d *defaultShoppingCart) CaculateStepPrice(purchaseQuantity int64, stepPrice gmodel.StepPriceJsonStruct, fittingPrice int64) (totalPrice, itemPrice int64, err error) {
//阶梯数量切片 l := len(stepPrice.PriceRange)
stepNum, err = format.StrSlicToIntSlice(strings.Split(*productPrice.StepNum, ",")) if l == 0 {
if err != nil { return 0, 0, errors.New("price range is not set")
logx.Error(err)
return 0, 0, nil, nil, errors.New(fmt.Sprintf("failed to parse step number:%d_%d", *productPrice.ProductId, *productPrice.SizeId))
} }
lenStepNum := len(stepNum) //遍历查询合适的价格
//阶梯价格切片 for k, v := range stepPrice.PriceRange {
stepPrice, err = format.StrSlicToIntSlice(strings.Split(*productPrice.StepPrice, ",")) //购买数量>起点
if err != nil { if purchaseQuantity > v.StartQuantity {
logx.Error(err) //最后一个 || 小于等于终点
return 0, 0, nil, nil, errors.New(fmt.Sprintf("failed to parse step price:%d_%d", *productPrice.ProductId, *productPrice.SizeId)) if k == l-1 || purchaseQuantity <= v.EndQuantity {
itemPrice = v.Price + fittingPrice
return itemPrice * purchaseQuantity, itemPrice, nil
} }
lenStepPrice := len(stepPrice)
if lenStepPrice == 0 || lenStepNum == 0 {
return 0, 0, nil, nil, errors.New(fmt.Sprintf("step price or step number is not set:%d_%d", *productPrice.ProductId, *productPrice.SizeId))
} }
//请求的数量 }
reqPurchaseQuantity := purchaseQuantity //遍历里面没有则返回第一个
//购买箱数 itemPrice = stepPrice.PriceRange[0].Price + fittingPrice
boxQuantity := int(math.Ceil(float64(reqPurchaseQuantity) / float64(*productPrice.EachBoxNum))) return itemPrice * purchaseQuantity, itemPrice, nil
//根据数量获取阶梯价格中对应的价格
itemPrice := step_price.GetCentStepPrice(boxQuantity, stepNum, stepPrice)
//如果有配件,单价也要加入配件价格
itemPrice += fittingPrice
//单个购物车总价
totalPrice = itemPrice * reqPurchaseQuantity
return itemPrice, totalPrice, stepNum, stepPrice, nil
} }

View File

@ -107,9 +107,10 @@ var (
CodeErrOrderCreatProductPriceAbsent = &StatusResponse{5304, "create order failed, price of product is absent"} // 订单创建失败,商品价格不存在 CodeErrOrderCreatProductPriceAbsent = &StatusResponse{5304, "create order failed, price of product is absent"} // 订单创建失败,商品价格不存在
CodeErrOrderCreatProductAccessoryAbsent = &StatusResponse{5305, "create order failed, accessory of product is absent"} // 订单创建失败,商品配件不存在 CodeErrOrderCreatProductAccessoryAbsent = &StatusResponse{5305, "create order failed, accessory of product is absent"} // 订单创建失败,商品配件不存在
CodeErrOrderCreatePrePaymentParam = &StatusResponse{5306, "create payment failed, the shipping address is illegal"} // 订单创建失败,商品配件不存在 CodeErrOrderCreatePrePaymentParam = &StatusResponse{5306, "create payment failed, the shipping address is illegal"} // 订单创建失败,商品配件不存在
CodeErrOrderCreatePrePaymentInfoNoFound = &StatusResponse{5307, "create payment failed, order info not found"} CodeErrOrderCreatePrePaymentInfoNoFound = &StatusResponse{5307, "order info not found"}
CodeErrOrderCreatePrePaymentPaidDeposit = &StatusResponse{5308, "create payment failed, order is paid"} CodeErrOrderCreatePrePaymentNoUnPaid = &StatusResponse{5308, "create payment failed, order is not unpaid"}
CodeErrOrderCreatePrePaymentTimeout = &StatusResponse{5309, "create payment failed, timeout"} CodeErrOrderCreatePrePaymentPaid = &StatusResponse{5309, "create payment failed, order is paid"}
CodeErrOrderCreatePrePaymentTimeout = &StatusResponse{5310, "create payment failed, timeout"}
) )
type Response struct { type Response struct {

View File

@ -20,8 +20,9 @@ func NewClient(ctx context.Context, c *Config) Client {
client := resty.New().SetBaseURL(c.BaseUrl) client := resty.New().SetBaseURL(c.BaseUrl)
// 设置超时时间为 5 分钟 // 设置超时时间为 5 分钟
if c.RequireTimeout == 0 {
client.SetTimeout(5 * time.Minute) client.SetTimeout(5 * time.Minute)
}
/* 传输链路 */ /* 传输链路 */
tracer := otel.GetTracerProvider().Tracer(trace.TraceName) tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
spanCtx, span := tracer.Start( spanCtx, span := tracer.Start(
@ -65,6 +66,7 @@ type (
HeaderData map[string]string `json:"header_data"` HeaderData map[string]string `json:"header_data"`
RetryCount int64 `json:"retry_count"` RetryCount int64 `json:"retry_count"`
RetryWaitTime int64 `json:"retry_wait_time"` RetryWaitTime int64 `json:"retry_wait_time"`
RequireTimeout time.Duration `json:"require_timeout"`
} }
defaultClient struct { defaultClient struct {
c *Config c *Config

25
utils/format/number.go Normal file
View File

@ -0,0 +1,25 @@
package format
import (
"fmt"
"strings"
)
// 数字变成带千分位的字符串
func NumToStringWithThousandthPercentile(number int64) string {
s := fmt.Sprintf("%d", number)
l := len(s)
if l <= 3 {
return s
}
r := l % 3 //前面第几位开始加入千分位
b := strings.Builder{}
for i := 0; i < l; i++ {
b.WriteString(string(s[i]))
if i+1 == r && i != l-1 {
b.WriteString(",")
r += 3
}
}
return b.String()
}

View File

@ -59,7 +59,7 @@ func MetadataModulePATCH(tx *gorm.DB, module string, tableStructPointer any, upd
WHEN metadata IS NULL THEN ? WHEN metadata IS NULL THEN ?
ELSE JSON_MERGE_PATCH(metadata, ?) ELSE JSON_MERGE_PATCH(metadata, ?)
END END
WHERE order_sn = '%s' and %s;` WHERE module = '%s' and %s;`
var err error var err error
var metadata []byte var metadata []byte
@ -191,3 +191,12 @@ func MetadataOrderPATCH(tx *gorm.DB, sql string, orderSn string, tableStructPoin
return nil return nil
} }
func GetGormTableName(tx *gorm.DB, tableStructPointer any) string {
stype := reflect.TypeOf(tableStructPointer)
if stype.Kind() == reflect.Pointer {
stype = stype.Elem()
}
tname := tx.NamingStrategy.TableName(stype.Name())
return tname
}

View File

@ -8,10 +8,7 @@ import (
) )
func TestCase1(t *testing.T) { func TestCase1(t *testing.T) {
u := gmodel.UserProfile{ u := gmodel.UserProfile{}
FirstName: "h",
LastName: "sm",
}
conn := initalize.InitMysql("fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen") conn := initalize.InitMysql("fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen")
err := fssql.MetadataModulePATCH(conn, "profile", gmodel.FsUserInfo{}, u, "id = ?", 90) err := fssql.MetadataModulePATCH(conn, "profile", gmodel.FsUserInfo{}, u, "id = ?", 90)

View File

@ -5,6 +5,7 @@ import (
"fusenapi/constants" "fusenapi/constants"
"fusenapi/model/gmodel" "fusenapi/model/gmodel"
"fusenapi/utils/format" "fusenapi/utils/format"
"strconv"
"time" "time"
) )
@ -112,6 +113,14 @@ func GetAmountInfoFormat(req *gmodel.AmountInfo) gmodel.AmountInfo {
} }
} }
// 处理商品数量
func GetPurchaseQuantity(req *gmodel.PurchaseQuantity) gmodel.PurchaseQuantity {
return gmodel.PurchaseQuantity{
Initiate: strconv.FormatInt(int64(req.Initiate.(float64)), 10),
Current: strconv.FormatInt(int64(req.Current.(float64)), 10),
}
}
// 生成订单编号 // 生成订单编号
func GenerateOrderNumber() string { func GenerateOrderNumber() string {
t := time.Now() t := time.Now()
@ -120,7 +129,7 @@ func GenerateOrderNumber() string {
return orderNumber return orderNumber
} }
// 初始化订单状态 // 初始化订单状态--链路
func GenerateOrderStatusLink(deliveryMethod int64, noTime time.Time, expectedTime time.Time) []gmodel.OrderStatus { func GenerateOrderStatusLink(deliveryMethod int64, noTime time.Time, expectedTime time.Time) []gmodel.OrderStatus {
var list []gmodel.OrderStatus var list []gmodel.OrderStatus
@ -142,6 +151,42 @@ func GenerateOrderStatusLink(deliveryMethod int64, noTime time.Time, expectedTim
return list return list
} }
// 更新订单状态--链路
func UpdateOrderStatusLink(statusLink []gmodel.OrderStatus, status gmodel.OrderStatus) []gmodel.OrderStatus {
var list []gmodel.OrderStatus
for _, v := range statusLink {
if v.StatusCode == status.StatusCode {
item := v
if status.StatusTitle != "" {
item.StatusTitle = status.StatusTitle
}
if status.StatusCode != 0 {
item.StatusCode = status.StatusCode
}
if status.Utime != nil {
item.Utime = status.Utime
}
if status.Ctime != nil {
item.Ctime = status.Ctime
}
if status.Metadata != nil {
item.Metadata = status.Metadata
}
if status.ExpectedTime != nil {
item.ExpectedTime = status.ExpectedTime
}
if status.Children != nil || len(status.Children) > 0 {
item.Children = status.Children
}
list = append(list, item)
} else {
list = append(list, v)
}
}
return list
}
// 获取订单状态 // 获取订单状态
func GetOrderStatusLinkUser(deliveryMethod int64, statusLink []gmodel.OrderStatus) []gmodel.OrderStatus { func GetOrderStatusLinkUser(deliveryMethod int64, statusLink []gmodel.OrderStatus) []gmodel.OrderStatus {
var list []gmodel.OrderStatus var list []gmodel.OrderStatus

View File

@ -29,7 +29,7 @@ type Pay interface {
} }
type GeneratePrepaymentReq struct { type GeneratePrepaymentReq struct {
OrderSn string `json:"order_sn"` // 订单编号 Metadata map[string]string `json:"metadata"` // 元数据
Amount int64 `json:"amount"` // 支付金额 Amount int64 `json:"amount"` // 支付金额
Currency string `json:"currency"` // 支付货币 Currency string `json:"currency"` // 支付货币
ProductName string `json:"product_name"` // 商品名称 ProductName string `json:"product_name"` // 商品名称

View File

@ -1,10 +1,10 @@
package pay package pay
import ( import (
"github.com/stripe/stripe-go/v74" "github.com/stripe/stripe-go/v75"
"github.com/stripe/stripe-go/v74/checkout/session" "github.com/stripe/stripe-go/v75/checkout/session"
"github.com/stripe/stripe-go/v74/paymentintent" "github.com/stripe/stripe-go/v75/paymentintent"
"github.com/stripe/stripe-go/v74/refund" "github.com/stripe/stripe-go/v75/refund"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
@ -50,7 +50,7 @@ func (stripePay *Stripe) GeneratePrepayment(req *GeneratePrepaymentReq) (res *Ge
case "session": case "session":
// session 方式 // session 方式
params := &stripe.CheckoutSessionParams{ params := &stripe.CheckoutSessionParams{
PaymentIntentData: &stripe.CheckoutSessionPaymentIntentDataParams{Metadata: map[string]string{"order_sn": req.OrderSn}}, PaymentIntentData: &stripe.CheckoutSessionPaymentIntentDataParams{Metadata: req.Metadata},
// Params: stripe.Params{Metadata: map[string]string{"order_id": "1111111111111"}}, // Params: stripe.Params{Metadata: map[string]string{"order_id": "1111111111111"}},
PaymentMethodTypes: stripe.StringSlice([]string{ PaymentMethodTypes: stripe.StringSlice([]string{
"card", "card",
@ -86,6 +86,9 @@ func (stripePay *Stripe) GeneratePrepayment(req *GeneratePrepaymentReq) (res *Ge
// "ideal", // "ideal",
}), }),
} }
for key, item := range req.Metadata {
params.AddMetadata(key, item)
}
resPaymentintent, err := paymentintent.New(params) resPaymentintent, err := paymentintent.New(params)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,22 +1,6 @@
package step_price package step_price
// 返回美元 // 旧的返回厘(即将废弃)
func GetStepPrice(minBuyNum int, stepNum []int, stepPrice []int) float64 {
if minBuyNum > stepNum[len(stepNum)-1] {
return float64(stepPrice[len(stepPrice)-1]) / float64(1000)
}
for k, v := range stepNum {
if minBuyNum <= v {
if k <= (len(stepPrice) - 1) {
return float64(stepPrice[k]) / float64(1000)
}
return float64(stepPrice[len(stepPrice)-1]) / float64(1000)
}
}
return float64(stepPrice[len(stepPrice)-1]) / float64(1000)
}
// 返回厘
func GetCentStepPrice(minBuyNum int, stepNum []int, stepPrice []int) int64 { func GetCentStepPrice(minBuyNum int, stepNum []int, stepPrice []int) int64 {
if minBuyNum > stepNum[len(stepNum)-1] { if minBuyNum > stepNum[len(stepNum)-1] {
return int64(stepPrice[len(stepPrice)-1]) return int64(stepPrice[len(stepPrice)-1])