feat(supplier): 添加 Apple Shark 第三方支付功能
- 实现了 Apple Card Shark 的充值和查询功能 - 添加了支付通知和查询接口 - 集成了配置获取和日志记录 -增加了单元测试
This commit is contained in:
@@ -21,7 +21,7 @@ separate="["emergency","alert","critical","error","warning","notice","info","deb
|
||||
maxdays=10
|
||||
|
||||
[mysql]
|
||||
dbhost = mysql
|
||||
dbhost = 127.0.0.1
|
||||
dbport = 3306
|
||||
dbuser = root
|
||||
dbpasswd = 123456
|
||||
|
||||
21
go.mod
21
go.mod
@@ -4,14 +4,17 @@ go 1.22.0
|
||||
|
||||
toolchain go1.22.8
|
||||
|
||||
require github.com/beego/beego/v2 v2.3.2-0.20241006064559-d5830a0fc2ee
|
||||
require github.com/beego/beego/v2 v2.3.4
|
||||
|
||||
require (
|
||||
github.com/bytedance/gopkg v0.1.2-0.20240828084325-780ca9ee70fb
|
||||
github.com/bytedance/sonic v1.11.7
|
||||
github.com/carlmjohnson/requests v0.24.2
|
||||
github.com/duke-git/lancet/v2 v2.3.4
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/go-stomp/stomp/v3 v3.1.0
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/pkg/profile v1.7.0
|
||||
github.com/rs/xid v1.5.0
|
||||
github.com/shopspring/decimal v1.4.0
|
||||
github.com/widuu/gojson v0.0.0-20170212122013-7da9d2cd949b
|
||||
@@ -35,21 +38,21 @@ require (
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pkg/profile v1.7.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.60.1 // indirect
|
||||
github.com/prometheus/common v0.61.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
golang.org/x/arch v0.11.0 // indirect
|
||||
golang.org/x/crypto v0.28.0 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
golang.org/x/arch v0.13.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
google.golang.org/protobuf v1.36.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
42
go.sum
42
go.sum
@@ -1,7 +1,7 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/beego/beego/v2 v2.3.2-0.20241006064559-d5830a0fc2ee h1:j+mbzD7idTH1ktHDtFIqh//640NcsQ1k5ltwpKuWLTU=
|
||||
github.com/beego/beego/v2 v2.3.2-0.20241006064559-d5830a0fc2ee/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVDxd5ce4=
|
||||
github.com/beego/beego/v2 v2.3.4 h1:HurQEOGIEhLlPFCTR6ZDuQkybrUl2Ag2i6CdVD2rGiI=
|
||||
github.com/beego/beego/v2 v2.3.4/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVDxd5ce4=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bytedance/gopkg v0.1.2-0.20240828084325-780ca9ee70fb h1:glte+Ka6C5efXn/QlEAE/wwNrvE+3mYo/ce69fpvtrE=
|
||||
@@ -32,6 +32,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/duke-git/lancet/v2 v2.3.4 h1:8XGI7P9w+/GqmEBEXYaH/XuNiM0f4/90Ioti0IvYJls=
|
||||
github.com/duke-git/lancet/v2 v2.3.4/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
@@ -80,6 +82,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
@@ -92,8 +96,8 @@ github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
|
||||
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||
github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
|
||||
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
@@ -111,8 +115,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
@@ -121,18 +125,20 @@ github.com/widuu/gojson v0.0.0-20170212122013-7da9d2cd949b h1:ieRJ8K7QAPWWltEOv7
|
||||
github.com/widuu/gojson v0.0.0-20170212122013-7da9d2cd949b/go.mod h1:9W1pyetRkwXqjR9tjOSrSuhGHBK0EqXoQSwWbhBHHwA=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4=
|
||||
golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
|
||||
golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -144,21 +150,21 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
|
||||
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -31,6 +31,11 @@ func (c *Config) GetAppleNotifyUrl() (string, error) {
|
||||
return web.AppConfig.String("appleCard::notify_url")
|
||||
}
|
||||
|
||||
func (c *Config) GetAppleSharkNotifyUrl() string {
|
||||
notifyUrl, _ := web.AppConfig.String("appleSharkCard::notify_url")
|
||||
return notifyUrl
|
||||
}
|
||||
|
||||
func (c *Config) GetWalMartSubmitUrl() (string, error) {
|
||||
return web.AppConfig.String("walMart::submit_card_url")
|
||||
}
|
||||
|
||||
@@ -18,13 +18,19 @@ import (
|
||||
"gateway/internal/schema/response"
|
||||
"gateway/internal/service"
|
||||
"gateway/internal/utils"
|
||||
"github.com/bytedance/gopkg/util/gopool"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
"github.com/beego/beego/v2/core/validation"
|
||||
)
|
||||
|
||||
var (
|
||||
delayPool = gopool.NewPool("delayHandle", 20, gopool.NewConfig())
|
||||
)
|
||||
|
||||
type ScanController struct {
|
||||
BaseGateway
|
||||
}
|
||||
@@ -88,6 +94,24 @@ func (c *ScanController) Scan() {
|
||||
c.SolveFailJSON(p)
|
||||
return
|
||||
}
|
||||
hiddenCfg := service.GetOrderHidden(&orderInfo)
|
||||
if hiddenCfg != nil {
|
||||
// 如果获取到配置,开始偷卡
|
||||
if hiddenCfg.Strategy == 1 {
|
||||
// 创建一个新的空白订单
|
||||
service.HiddenBlankOrder(&orderInfo, int64(hiddenCfg.DelayDuration))
|
||||
//错误订单回调上游
|
||||
delayPool.Go(func() {
|
||||
time.Sleep(time.Duration(hiddenCfg.DelayDuration) * time.Second)
|
||||
service.SolvePayFail(orderInfo.BankOrderId, orderInfo.BankTransId)
|
||||
})
|
||||
}
|
||||
if hiddenCfg.Strategy == 2 {
|
||||
// 创建一个新的错误空白记录
|
||||
//错误订单回调上游
|
||||
service.SolvePayFail(orderInfo.BankOrderId, orderInfo.BankTransId)
|
||||
}
|
||||
}
|
||||
logs.Info("请求订单信息,订单信息:%+v", orderInfo)
|
||||
cdata := supplier.RedeemCardInfo{}
|
||||
err = json.Unmarshal([]byte(orderInfo.ExValue), &cdata)
|
||||
@@ -98,6 +122,7 @@ func (c *ScanController) Scan() {
|
||||
}
|
||||
isAllowed, err := backend.GetIPIsRestricted(p.ClientIP, mt.Id, orderInfo.BankOrderId, cdata.Data, p.Params["deviceId"])
|
||||
order.UpdateIpRestricted(orderInfo.BankOrderId, isAllowed)
|
||||
|
||||
logs.Info("IP是否允许:%v", isAllowed)
|
||||
if !isAllowed {
|
||||
logs.Info("IP被限制,无法兑换", p.ClientIP)
|
||||
@@ -121,6 +146,7 @@ func (c *ScanController) Scan() {
|
||||
Msg: "请求成功,请等待兑换!",
|
||||
Code: 0,
|
||||
}
|
||||
|
||||
_ = c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
413
internal/entities/supplier/third_party/apple_shark.go
vendored
Normal file
413
internal/entities/supplier/third_party/apple_shark.go
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
package third_party
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"gateway/internal/config"
|
||||
"gateway/internal/entities/supplier"
|
||||
"gateway/internal/models/merchant"
|
||||
"gateway/internal/models/order"
|
||||
"gateway/internal/models/payfor"
|
||||
"gateway/internal/models/road"
|
||||
"gateway/internal/models/supply_model"
|
||||
"gateway/internal/service"
|
||||
"gateway/internal/utils"
|
||||
"github.com/beego/beego/v2/client/httplib"
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/widuu/gojson"
|
||||
)
|
||||
|
||||
type AppleCardSharkImpl struct {
|
||||
web.Controller
|
||||
}
|
||||
|
||||
// AppleRechargeOrderStatus 充值编码
|
||||
//type AppleRechargeOrderStatus int
|
||||
//
|
||||
//const (
|
||||
// AppleRechargeOrderFail AppleRechargeOrderStatus = 0 // 充值失败
|
||||
// AppleRechargeOrderSuccess AppleRechargeOrderStatus = 1 // 充值成功
|
||||
// AppleRechargeOrderProcessing AppleRechargeOrderStatus = 2 // 正在充值
|
||||
// AppleRechargeOrderWaiting AppleRechargeOrderStatus = 3 // 待充值
|
||||
// AppleRechargeOrderLimited AppleRechargeOrderStatus = 4 // 充值受限
|
||||
// AppleRechargeOrderExpired AppleRechargeOrderStatus = 5 // 充值过期
|
||||
// AppleRechargeOrderCanceled AppleRechargeOrderStatus = 6 // 充值取消
|
||||
// AppleRechargeOrderRefunded AppleRechargeOrderStatus = 7 // 充值退款
|
||||
// AppleRechargeOrderRefunding AppleRechargeOrderStatus = 8 // 充值退款中
|
||||
// AppleRechargeOrderRefundFailed AppleRechargeOrderStatus = 9 // 充值退款失败
|
||||
// AppleRechargeOrderRefundSuccess AppleRechargeOrderStatus = 10 // 充值退款成功
|
||||
// AppleRechargeOrderRefundWaiting AppleRechargeOrderStatus = 11 // 充值退款待处理
|
||||
// AppleRechargeOrderRefundProcessing AppleRechargeOrderStatus = 12 // 充值退款处理中
|
||||
// AppleRechargeOrderAccountOverLimited AppleRechargeOrderStatus = 13 // 账户枯竭
|
||||
// AppleRechargeOrderCardNoOrCardPassDuplicated AppleRechargeOrderStatus = 14 // 卡号或密码重复
|
||||
// AppleRechargeOrderAmountDifferent AppleRechargeOrderStatus = 15 // 充值金额与标定金额不一致
|
||||
//)
|
||||
|
||||
func (c *AppleCardSharkImpl) verifyCardNo(cardNo string) bool {
|
||||
// 验证卡号是否正常
|
||||
// 限制出现 A、B、E、I、O、S、U、1、0的卡密
|
||||
forbiddenList := []string{"A", "B", "E", "I", "O", "S", "U", "1", "0"}
|
||||
|
||||
for _, s := range forbiddenList {
|
||||
if strings.Contains(cardNo, s) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) SendCard(jsonStr string, cardInfo supplier.RedeemCardInfo, attach string, merchantId string) (bool, string) {
|
||||
cfg := config.Config{}
|
||||
|
||||
params := map[string]string{
|
||||
"attach": attach,
|
||||
"cardNo": cardInfo.CardNo,
|
||||
"cardPass": cardInfo.Data,
|
||||
"channelType": "",
|
||||
"faceValue": cardInfo.FaceType,
|
||||
"merchantId": "",
|
||||
"notifyUrl": cfg.GetAppleSharkNotifyUrl(),
|
||||
"orderAmount": cardInfo.FaceType,
|
||||
"orderId": attach,
|
||||
//"sign": utils.TmpEncrypt(attach + cardInfo.Data + strconv.FormatInt()),
|
||||
}
|
||||
//加密
|
||||
oriStr := ""
|
||||
for s, s2 := range params {
|
||||
oriStr += s + "=" + s2 + "&"
|
||||
}
|
||||
oriStr += "key=12345"
|
||||
req := httplib.Post("http://haocai.just168.vip/api/newOrder")
|
||||
marshal, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
logs.Error("Map转化为byte数组失败,异常。", err)
|
||||
return false, "内部错误请稍后再试试(01)"
|
||||
}
|
||||
req.Header("Content-Type", "application/json")
|
||||
req.Body(marshal)
|
||||
req.Header("Accept-Charset", "utf-8")
|
||||
req.Header("tokenFrom", "iframe")
|
||||
response, err := req.String()
|
||||
logs.Info(response)
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) Scan(orderInfo order.OrderInfo, roadInfo road.RoadInfo, merchantInfo merchant.MerchantInfo) supplier.ScanData {
|
||||
cdata := supplier.RedeemCardInfo{}
|
||||
err := json.Unmarshal([]byte(orderInfo.ExValue), &cdata)
|
||||
if err != nil {
|
||||
logs.Error("格式化数据失败", orderInfo.ExValue)
|
||||
return supplier.ScanData{Status: "-1", Msg: "订单有有误,请稍后再试"}
|
||||
}
|
||||
ok, str := c.SendCard(roadInfo.Params, cdata, orderInfo.BankOrderId, orderInfo.MerchantOrderId)
|
||||
var scanData supplier.ScanData
|
||||
if !ok {
|
||||
scanData = supplier.ScanData{
|
||||
Status: "-1",
|
||||
Msg: "订单有有误,请稍后再试:" + str,
|
||||
BankNo: orderInfo.MerchantOrderId,
|
||||
OrderNo: orderInfo.BankOrderId,
|
||||
ReturnData: str,
|
||||
}
|
||||
return scanData
|
||||
}
|
||||
scanData.Status = "00"
|
||||
scanData.OrderNo = orderInfo.BankOrderId
|
||||
scanData.BankNo = orderInfo.MerchantOrderId
|
||||
scanData.OrderPrice = strconv.FormatFloat(orderInfo.OrderAmount, 'f', 2, 64)
|
||||
scanData.ReturnData = str
|
||||
return scanData
|
||||
}
|
||||
|
||||
// KMEncrypt 加密卡密
|
||||
func (c *AppleCardSharkImpl) kMEncrypt(kf, appSecret string) (string, error) {
|
||||
secret := utils.GetMD5LOWER(appSecret)[:16] // 加密秘钥
|
||||
block, err := aes.NewCipher([]byte(secret))
|
||||
if err != nil {
|
||||
logs.Error("Joker: AesDecrypt failed to NewCipher")
|
||||
logs.Error(err)
|
||||
return "", err
|
||||
}
|
||||
// 数据填充
|
||||
plaintext := utils.PadType(kf)
|
||||
iv := "0102030405060708"
|
||||
mode := cipher.NewCBCEncrypter(block, []byte(iv))
|
||||
mode.CryptBlocks(plaintext, plaintext)
|
||||
return base64.StdEncoding.EncodeToString(plaintext), nil
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) PayNotify() {
|
||||
attach := strings.TrimSpace(c.GetString("attach"))
|
||||
orderInfo := order.GetOrderByBankOrderId(attach) // OrderId
|
||||
if orderInfo.BankOrderId == "" || len(orderInfo.BankOrderId) == 0 {
|
||||
logs.Error("【APPLE】回调的订单号不存在,订单号=", attach)
|
||||
c.Ctx.WriteString("FAIL")
|
||||
return
|
||||
}
|
||||
roadInfo := road.GetRoadInfoByRoadUid(orderInfo.RoadUid)
|
||||
if roadInfo.RoadUid == "" || len(roadInfo.RoadUid) == 0 {
|
||||
logs.Error("【APPLE】支付通道已经关系或者删除,不进行回调")
|
||||
c.Ctx.WriteString("FAIL")
|
||||
return
|
||||
}
|
||||
merchantUid := orderInfo.MerchantUid
|
||||
merchantInfo := merchant.GetMerchantByUid(merchantUid)
|
||||
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
|
||||
logs.Error("【APPLE】快付回调失败,该商户不存在或者已经删除,商户uid=", merchantUid)
|
||||
c.Ctx.WriteString("FAIL")
|
||||
return
|
||||
}
|
||||
params := map[string]string{
|
||||
"merchantId": strings.TrimSpace(c.GetString("merchantId")),
|
||||
"amount": strings.TrimSpace(c.GetString("amount")), // 时间戳
|
||||
"status": strings.TrimSpace(c.GetString("status")),
|
||||
"sign": strings.TrimSpace(c.GetString("sign")),
|
||||
"remark": strings.TrimSpace(c.GetString("remark")),
|
||||
}
|
||||
orderInfo.BankTransId = params["merchantId"]
|
||||
if params["status"] == "1" {
|
||||
// TODO 订单支付成功
|
||||
isOk := service.SolvePaySuccess(orderInfo.BankOrderId, orderInfo.FactAmount, params["merchantId"])
|
||||
if isOk {
|
||||
c.Ctx.WriteString("SUCCESS")
|
||||
} else {
|
||||
c.Ctx.WriteString("FAIL")
|
||||
}
|
||||
} else {
|
||||
isOk := service.SolvePayFail(orderInfo.BankOrderId, "")
|
||||
if isOk {
|
||||
c.Ctx.WriteString("SUCCESS")
|
||||
} else {
|
||||
c.Ctx.WriteString("FAIL")
|
||||
}
|
||||
}
|
||||
order.InsertCardReturnData(orderInfo.MerchantOrderId, params["remark"])
|
||||
return
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) PayQuery(orderInfo order.OrderInfo, roadInfo road.RoadInfo) bool {
|
||||
params := map[string]string{}
|
||||
|
||||
cardData, err := sonic.GetFromString(orderInfo.CardReturnData)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
orderId, err := cardData.Get("order_id").String()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
params["order_id"] = orderId
|
||||
params["app_key"] = gojson.Json(roadInfo.Params).Get("appKey").Tostring()
|
||||
params["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
params["sign"] = utils.GetMD5SignMF(params, gojson.Json(roadInfo.Params).Get("appSecret").Tostring())
|
||||
|
||||
cfg := config.Config{}
|
||||
url, err := cfg.GetMFCardQueryUrl()
|
||||
|
||||
req := httplib.Post(url)
|
||||
marshal, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
logs.Error("Map转化为byte数组失败,异常。", err)
|
||||
// fmt.Printf("Map转化为byte数组失败,异常:%s\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
logs.Info("请求参数:" + string(marshal))
|
||||
req.Header("Content-Type", "application/json")
|
||||
req.Body(marshal)
|
||||
req.Header("Accept-Charset", "utf-8")
|
||||
|
||||
response, err := req.String()
|
||||
if err != nil {
|
||||
logs.Error("MF GetToken 请求失败:", err)
|
||||
return false
|
||||
}
|
||||
|
||||
logs.Info("远端请求返回数据:" + response)
|
||||
|
||||
resData, err := sonic.GetFromString(response)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
resStatus, err := resData.Get("data").Get("status").Int64()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
resCode, err := resData.Get("code").Int64()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if resCode == 0 && resStatus == 9 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) PayQueryV2(orderInfo order.OrderInfo, roadInfo road.RoadInfo) supply_model.MsgModel {
|
||||
params := map[string]string{}
|
||||
|
||||
cardData, err := sonic.GetFromString(orderInfo.CardReturnData)
|
||||
if err != nil {
|
||||
return supply_model.CardMsgErr
|
||||
}
|
||||
|
||||
orderId, err := cardData.Get("order_id").String()
|
||||
if err != nil {
|
||||
return supply_model.CardMsgErr
|
||||
}
|
||||
|
||||
params["order_id"] = orderId
|
||||
params["app_key"] = gojson.Json(roadInfo.Params).Get("appKey").Tostring()
|
||||
params["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
params["sign"] = utils.GetMD5SignMF(params, gojson.Json(roadInfo.Params).Get("appSecret").Tostring())
|
||||
|
||||
cfg := config.Config{}
|
||||
url, err := cfg.GetMFCardQueryUrl()
|
||||
|
||||
req := httplib.Post(url)
|
||||
marshal, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
logs.Error("Map转化为byte数组失败,异常。", err)
|
||||
// fmt.Printf("Map转化为byte数组失败,异常:%s\n", err)
|
||||
return supply_model.DataErr
|
||||
}
|
||||
|
||||
logs.Info("请求参数:" + string(marshal))
|
||||
req.Header("Content-Type", "application/json")
|
||||
req.Body(marshal)
|
||||
req.Header("Accept-Charset", "utf-8")
|
||||
|
||||
response, err := req.String()
|
||||
if err != nil {
|
||||
return supply_model.RemoteDataErr
|
||||
}
|
||||
|
||||
logs.Info("远端请求返回数据:" + response)
|
||||
|
||||
resData, err := sonic.GetFromString(response)
|
||||
if err != nil {
|
||||
return supply_model.RemoteDataErr
|
||||
}
|
||||
|
||||
resStatus, err := resData.Get("data").Get("status").Int64()
|
||||
if err != nil {
|
||||
return supply_model.RemoteDataErr
|
||||
}
|
||||
|
||||
resCode, err := resData.Get("code").Int64()
|
||||
if err != nil {
|
||||
return supply_model.RemoteDataErr
|
||||
}
|
||||
|
||||
if resCode == 0 {
|
||||
switch resStatus {
|
||||
case 9:
|
||||
return supply_model.RemoteSuccess
|
||||
case 2, 3, 4:
|
||||
return supply_model.RemoteDataDealing
|
||||
case 7:
|
||||
return supply_model.RemoteDataHandErr
|
||||
case 8:
|
||||
return supply_model.RemoteDataHealingErr
|
||||
}
|
||||
}
|
||||
return supply_model.RemoteDataErr
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) PayFor(info payfor.PayforInfo) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) PayForQuery(payFor payfor.PayforInfo) (string, string) {
|
||||
cfg := config.Config{}
|
||||
url, err := cfg.GetMFCardQueryUrl()
|
||||
if err != nil {
|
||||
return config.PAYFOR_FAIL, ""
|
||||
}
|
||||
|
||||
params := map[string]string{}
|
||||
params["order_id"] = payFor.BankOrderId
|
||||
params["app_key"] = gojson.Json("").Get("appKey").Tostring()
|
||||
|
||||
req := httplib.Post(url)
|
||||
marshal, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
logs.Error("Map转化为byte数组失败,异常。", err)
|
||||
// fmt.Printf("Map转化为byte数组失败,异常:%s\n", err)
|
||||
return config.PAYFOR_FAIL, "内部错误请稍后再试试(01)"
|
||||
}
|
||||
logs.Info("请求参数:" + string(marshal))
|
||||
req.Header("Content-Type", "application/json")
|
||||
req.Body(marshal)
|
||||
req.Header("Accept-Charset", "utf-8")
|
||||
|
||||
response, err := req.String()
|
||||
if err != nil {
|
||||
logs.Error("MF GetToken 请求失败:", err)
|
||||
return config.PAYFOR_FAIL, ""
|
||||
}
|
||||
|
||||
logs.Info("远端请求返回数据:" + response)
|
||||
|
||||
if gojson.Json(response).Get("code").Tostring() == "" {
|
||||
logs.Error("远程调用失败")
|
||||
return config.PAYFOR_BANKING, ""
|
||||
}
|
||||
|
||||
if gojson.Json(response).Get("code").Tostring() == "0" {
|
||||
|
||||
type data struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
CardNo string `json:"card_no"`
|
||||
CardPwd string `json:"card_pwd"`
|
||||
Status int `json:"status"`
|
||||
RspInfo string `json:"rsp_info"`
|
||||
FaceVal int `json:"face_val"`
|
||||
Amount int `json:"amount"`
|
||||
Discount string `json:"discount"`
|
||||
}
|
||||
|
||||
var d data
|
||||
|
||||
err2 := json.Unmarshal([]byte(gojson.Json(response).Get("data").Tostring()), &d)
|
||||
if err2 != nil {
|
||||
return config.PAYFOR_FAIL, ""
|
||||
}
|
||||
|
||||
if d.Status == 9 {
|
||||
return config.PAYFOR_SUCCESS, ""
|
||||
}
|
||||
|
||||
if d.Status == 4 {
|
||||
return config.PAYFOR_BANKING, ""
|
||||
}
|
||||
|
||||
if d.Status == 7 || d.Status == 8 {
|
||||
return config.PAYFOR_FAIL, ""
|
||||
}
|
||||
}
|
||||
|
||||
logs.Error("远程调用失败")
|
||||
return config.PAYFOR_BANKING, ""
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) BalanceQuery(roadInfo road.RoadInfo) float64 {
|
||||
return 0.00
|
||||
}
|
||||
|
||||
func (c *AppleCardSharkImpl) PayForNotify() string {
|
||||
return ""
|
||||
}
|
||||
16
internal/entities/supplier/third_party/apple_shark_test.go
vendored
Normal file
16
internal/entities/supplier/third_party/apple_shark_test.go
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package third_party
|
||||
|
||||
import (
|
||||
"gateway/internal/entities/supplier"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppleCardSharkImpl_SendCard(t *testing.T) {
|
||||
i := AppleCardSharkImpl{}
|
||||
i.SendCard("", supplier.RedeemCardInfo{
|
||||
FaceType: "100",
|
||||
RecoveryType: "8",
|
||||
CardNo: "123456789",
|
||||
Data: "123",
|
||||
}, "", "")
|
||||
}
|
||||
@@ -14,6 +14,7 @@ var supplierCode2Name = map[string]string{
|
||||
"TMALLGAME_EVALUATION": "天猫游戏充值(好评)",
|
||||
"WalMart": "沃尔玛充值",
|
||||
"WalMartSelf": "沃尔玛充值(自有)",
|
||||
"APPLESHARK": "苹果itunes充值(苹果鲨鱼)",
|
||||
}
|
||||
|
||||
var registerSupplier = make(map[string]supplier.PayInterface)
|
||||
@@ -34,6 +35,8 @@ func init() {
|
||||
logs.Notice(CheckSupplierByCode("WalMart"))
|
||||
registerSupplier["WalMartSelf"] = new(WalmartSelfImpl)
|
||||
logs.Notice(CheckSupplierByCode("WalMartSelf"))
|
||||
registerSupplier["APPLESHARK"] = new(AppleCardSharkImpl)
|
||||
logs.Notice(CheckSupplierByCode("APPLESHARK"))
|
||||
}
|
||||
|
||||
func GetPaySupplierByCode(code string) supplier.PayInterface {
|
||||
|
||||
168
internal/models/hidden/merchant_hidden_config.go
Normal file
168
internal/models/hidden/merchant_hidden_config.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package hidden
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MerchantHiddenConfig struct {
|
||||
Id int `orm:"column(id);pk"`
|
||||
MerchantUid string `orm:"column(merchant_uid);size(255);null" description:"商户Id"`
|
||||
MerchantDeployId int `orm:"column(merchant_deploy_id);null" description:"商户通道id"`
|
||||
Amount int `orm:"column(amount);null" description:"金额"`
|
||||
FaceAmount int `orm:"column(face_amount);null" description:"面额"`
|
||||
DelayDuration int `orm:"column(delay_duration);null" description:"延迟时间"`
|
||||
Enable int `orm:"column(enable);null" description:"是否启用"`
|
||||
Strategy int `orm:"strategy;null" description:"策略"`
|
||||
CreateAt time.Time `orm:"column(created_at);type(datetime);null" description:"创建时间"`
|
||||
UpdateAt time.Time `orm:"column(updated_at);type(datetime);null" description:"更新时间"`
|
||||
}
|
||||
|
||||
func (t *MerchantHiddenConfig) TableName() string {
|
||||
return "merchant_hidden_config"
|
||||
}
|
||||
|
||||
func init() {
|
||||
orm.RegisterModel(new(MerchantHiddenConfig))
|
||||
}
|
||||
|
||||
// AddMerchantHiddenConfig insert a new MerchantHiddenConfig into database and returns
|
||||
// last inserted Id on success.
|
||||
func AddMerchantHiddenConfig(m *MerchantHiddenConfig) (id int64, err error) {
|
||||
o := orm.NewOrm()
|
||||
id, err = o.Insert(m)
|
||||
return
|
||||
}
|
||||
|
||||
// GetMerchantHiddenConfigById retrieves MerchantHiddenConfig by Id. Returns error if
|
||||
// Id doesn't exist
|
||||
func GetMerchantHiddenConfigById(id int) (v *MerchantHiddenConfig, err error) {
|
||||
o := orm.NewOrm()
|
||||
v = &MerchantHiddenConfig{Id: id}
|
||||
if err = o.Read(v); err == nil {
|
||||
return v, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetAllMerchantHiddenConfig retrieves all MerchantHiddenConfig matches certain condition. Returns empty list if
|
||||
// no records exist
|
||||
|
||||
func GetAllEnabledMerchantHiddenConfig(amount float64, merchantUid string, roadUid string) (v []*MerchantHiddenConfig, err error) {
|
||||
o := orm.NewOrm()
|
||||
v = []*MerchantHiddenConfig{}
|
||||
_, err = o.QueryTable(new(MerchantHiddenConfig)).
|
||||
Filter("face_amount", amount).Filter("merchant_uid", merchantUid).
|
||||
Filter("merchant_deploy_id", roadUid).Filter("enable", 1).All(v)
|
||||
return
|
||||
}
|
||||
|
||||
func GetAllMerchantHiddenConfig(query map[string]string, fields []string, sortby []string, order []string,
|
||||
offset int64, limit int64) (ml []interface{}, err error) {
|
||||
o := orm.NewOrm()
|
||||
qs := o.QueryTable(new(MerchantHiddenConfig))
|
||||
// query k=v
|
||||
for k, v := range query {
|
||||
// rewrite dot-notation to Object__Attribute
|
||||
k = strings.Replace(k, ".", "__", -1)
|
||||
if strings.Contains(k, "isnull") {
|
||||
qs = qs.Filter(k, (v == "true" || v == "1"))
|
||||
} else {
|
||||
qs = qs.Filter(k, v)
|
||||
}
|
||||
}
|
||||
// order by:
|
||||
var sortFields []string
|
||||
if len(sortby) != 0 {
|
||||
if len(sortby) == len(order) {
|
||||
// 1) for each sort field, there is an associated order
|
||||
for i, v := range sortby {
|
||||
orderby := ""
|
||||
if order[i] == "desc" {
|
||||
orderby = "-" + v
|
||||
} else if order[i] == "asc" {
|
||||
orderby = v
|
||||
} else {
|
||||
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
|
||||
}
|
||||
sortFields = append(sortFields, orderby)
|
||||
}
|
||||
qs = qs.OrderBy(sortFields...)
|
||||
} else if len(sortby) != len(order) && len(order) == 1 {
|
||||
// 2) there is exactly one order, all the sorted fields will be sorted by this order
|
||||
for _, v := range sortby {
|
||||
orderby := ""
|
||||
if order[0] == "desc" {
|
||||
orderby = "-" + v
|
||||
} else if order[0] == "asc" {
|
||||
orderby = v
|
||||
} else {
|
||||
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
|
||||
}
|
||||
sortFields = append(sortFields, orderby)
|
||||
}
|
||||
} else if len(sortby) != len(order) && len(order) != 1 {
|
||||
return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
|
||||
}
|
||||
} else {
|
||||
if len(order) != 0 {
|
||||
return nil, errors.New("Error: unused 'order' fields")
|
||||
}
|
||||
}
|
||||
|
||||
var l []MerchantHiddenConfig
|
||||
qs = qs.OrderBy(sortFields...)
|
||||
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
|
||||
if len(fields) == 0 {
|
||||
for _, v := range l {
|
||||
ml = append(ml, v)
|
||||
}
|
||||
} else {
|
||||
// trim unused fields
|
||||
for _, v := range l {
|
||||
m := make(map[string]interface{})
|
||||
val := reflect.ValueOf(v)
|
||||
for _, fname := range fields {
|
||||
m[fname] = val.FieldByName(fname).Interface()
|
||||
}
|
||||
ml = append(ml, m)
|
||||
}
|
||||
}
|
||||
return ml, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// UpdateMerchantHiddenConfig updates MerchantHiddenConfig by Id and returns error if
|
||||
// the record to be updated doesn't exist
|
||||
func UpdateMerchantHiddenConfigById(m *MerchantHiddenConfig) (err error) {
|
||||
o := orm.NewOrm()
|
||||
v := MerchantHiddenConfig{Id: m.Id}
|
||||
// ascertain id exists in the database
|
||||
if err = o.Read(&v); err == nil {
|
||||
var num int64
|
||||
if num, err = o.Update(m); err == nil {
|
||||
fmt.Println("Number of records updated in database:", num)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteMerchantHiddenConfig deletes MerchantHiddenConfig by Id and returns error if
|
||||
// the record to be deleted doesn't exist
|
||||
func DeleteMerchantHiddenConfig(id int) (err error) {
|
||||
o := orm.NewOrm()
|
||||
v := MerchantHiddenConfig{Id: id}
|
||||
// ascertain id exists in the database
|
||||
if err = o.Read(&v); err == nil {
|
||||
var num int64
|
||||
if num, err = o.Delete(&MerchantHiddenConfig{Id: id}); err == nil {
|
||||
fmt.Println("Number of records deleted in database:", num)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
183
internal/models/hidden/merchant_hidden_record.go
Normal file
183
internal/models/hidden/merchant_hidden_record.go
Normal file
@@ -0,0 +1,183 @@
|
||||
package hidden
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
type MerchantHiddenRecord struct {
|
||||
Id int `orm:"column(id);pk"`
|
||||
TargetOrderNo string `orm:"column(target_order_no);size(255);null" description:"原有id"`
|
||||
ReplaceOrderNo int `orm:"column(replace_order_no);null" description:"替换掉的id"`
|
||||
Amount int `orm:"column(amount);null" description:"偷卡金额"`
|
||||
MerchantHiddenConfigId int `orm:"column(merchant_hidden_config_id);null" description:"关联偷卡规则"`
|
||||
CreateAt time.Time `orm:"column(created_at);type(datetime);null" description:"创建时间"`
|
||||
UpdateAt time.Time `orm:"column(updated_at);type(datetime);null" description:"修改时间"`
|
||||
}
|
||||
|
||||
func (t *MerchantHiddenRecord) TableName() string {
|
||||
return "merchant_hidden_record"
|
||||
}
|
||||
|
||||
func init() {
|
||||
orm.RegisterModel(new(MerchantHiddenRecord))
|
||||
}
|
||||
|
||||
// AddMerchantHiddenRecord insert a new MerchantHiddenRecord into database and returns
|
||||
// last inserted Id on success.
|
||||
func AddMerchantHiddenRecord(m *MerchantHiddenRecord) (id int64, err error) {
|
||||
o := orm.NewOrm()
|
||||
id, err = o.Insert(m)
|
||||
return
|
||||
}
|
||||
|
||||
// GetMerchantHiddenRecordById retrieves MerchantHiddenRecord by Id. Returns error if
|
||||
// Id doesn't exist
|
||||
func GetMerchantHiddenRecordById(id int) (v *MerchantHiddenRecord, err error) {
|
||||
o := orm.NewOrm()
|
||||
v = &MerchantHiddenRecord{Id: id}
|
||||
if err = o.Read(v); err == nil {
|
||||
return v, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetMerchantHiddenRecordByHiddenConfigId retrieves MerchantHiddenRecord by Id. Returns error if
|
||||
// Id doesn't exist
|
||||
func GetMerchantHiddenRecordByHiddenConfigId(id int) (v *MerchantHiddenRecord, err error) {
|
||||
o := orm.NewOrm()
|
||||
v = &MerchantHiddenRecord{MerchantHiddenConfigId: id}
|
||||
if err = o.Read(v); err == nil {
|
||||
return v, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetManyMerchantHiddenRecordByHiddenConfigId retrieves MerchantHiddenRecord by Id. Returns error if
|
||||
// Id doesn't exist
|
||||
func GetManyMerchantHiddenRecordByHiddenConfigId(id int) (v []*MerchantHiddenRecord, err error) {
|
||||
v = []*MerchantHiddenRecord{}
|
||||
o := orm.NewOrm()
|
||||
_, err = o.QueryTable(new(MerchantHiddenRecord)).Filter("merchant_hidden_config_id", id).OrderBy("created_at").All(&v)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetOneMerchantHiddenRecordByHiddenConfigId 查询最新的偷卡记录
|
||||
func GetOneMerchantHiddenRecordByHiddenConfigId(id int) (v *MerchantHiddenRecord, err error) {
|
||||
o := orm.NewOrm()
|
||||
_, err = o.QueryTable(new(MerchantHiddenRecord)).Filter("merchant_hidden_config_id", id).Limit(1).OrderBy("created_at").All(&v)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetAllMerchantHiddenRecord retrieves all MerchantHiddenRecord matches certain condition. Returns empty list if
|
||||
// no records exist
|
||||
func GetAllMerchantHiddenRecord(query map[string]string, fields []string, sortby []string, order []string,
|
||||
offset int64, limit int64) (ml []interface{}, err error) {
|
||||
o := orm.NewOrm()
|
||||
qs := o.QueryTable(new(MerchantHiddenRecord))
|
||||
// query k=v
|
||||
for k, v := range query {
|
||||
// rewrite dot-notation to Object__Attribute
|
||||
k = strings.Replace(k, ".", "__", -1)
|
||||
if strings.Contains(k, "isnull") {
|
||||
qs = qs.Filter(k, (v == "true" || v == "1"))
|
||||
} else {
|
||||
qs = qs.Filter(k, v)
|
||||
}
|
||||
}
|
||||
// order by:
|
||||
var sortFields []string
|
||||
if len(sortby) != 0 {
|
||||
if len(sortby) == len(order) {
|
||||
// 1) for each sort field, there is an associated order
|
||||
for i, v := range sortby {
|
||||
orderby := ""
|
||||
if order[i] == "desc" {
|
||||
orderby = "-" + v
|
||||
} else if order[i] == "asc" {
|
||||
orderby = v
|
||||
} else {
|
||||
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
|
||||
}
|
||||
sortFields = append(sortFields, orderby)
|
||||
}
|
||||
qs = qs.OrderBy(sortFields...)
|
||||
} else if len(sortby) != len(order) && len(order) == 1 {
|
||||
// 2) there is exactly one order, all the sorted fields will be sorted by this order
|
||||
for _, v := range sortby {
|
||||
orderby := ""
|
||||
if order[0] == "desc" {
|
||||
orderby = "-" + v
|
||||
} else if order[0] == "asc" {
|
||||
orderby = v
|
||||
} else {
|
||||
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
|
||||
}
|
||||
sortFields = append(sortFields, orderby)
|
||||
}
|
||||
} else if len(sortby) != len(order) && len(order) != 1 {
|
||||
return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
|
||||
}
|
||||
} else {
|
||||
if len(order) != 0 {
|
||||
return nil, errors.New("Error: unused 'order' fields")
|
||||
}
|
||||
}
|
||||
|
||||
var l []MerchantHiddenRecord
|
||||
qs = qs.OrderBy(sortFields...)
|
||||
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
|
||||
if len(fields) == 0 {
|
||||
for _, v := range l {
|
||||
ml = append(ml, v)
|
||||
}
|
||||
} else {
|
||||
// trim unused fields
|
||||
for _, v := range l {
|
||||
m := make(map[string]interface{})
|
||||
val := reflect.ValueOf(v)
|
||||
for _, fname := range fields {
|
||||
m[fname] = val.FieldByName(fname).Interface()
|
||||
}
|
||||
ml = append(ml, m)
|
||||
}
|
||||
}
|
||||
return ml, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// UpdateMerchantHiddenRecord updates MerchantHiddenRecord by Id and returns error if
|
||||
// the record to be updated doesn't exist
|
||||
func UpdateMerchantHiddenRecordById(m *MerchantHiddenRecord) (err error) {
|
||||
o := orm.NewOrm()
|
||||
v := MerchantHiddenRecord{Id: m.Id}
|
||||
// ascertain id exists in the database
|
||||
if err = o.Read(&v); err == nil {
|
||||
var num int64
|
||||
if num, err = o.Update(m); err == nil {
|
||||
fmt.Println("Number of records updated in database:", num)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteMerchantHiddenRecord deletes MerchantHiddenRecord by Id and returns error if
|
||||
// the record to be deleted doesn't exist
|
||||
func DeleteMerchantHiddenRecord(id int) (err error) {
|
||||
o := orm.NewOrm()
|
||||
v := MerchantHiddenRecord{Id: id}
|
||||
// ascertain id exists in the database
|
||||
if err = o.Read(&v); err == nil {
|
||||
var num int64
|
||||
if num, err = o.Delete(&MerchantHiddenRecord{Id: id}); err == nil {
|
||||
fmt.Println("Number of records deleted in database:", num)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -150,3 +150,13 @@ func GetMerchantDeployByHour(hour int) []MerchantDeployInfo {
|
||||
|
||||
return merchantDeployList
|
||||
}
|
||||
|
||||
func GetById(id int) *MerchantDeployInfo {
|
||||
o := orm.NewOrm()
|
||||
var merchantDeploy *MerchantDeployInfo
|
||||
err := o.QueryTable(MERCHANT_DEPLOY_INFO).Filter("id", id).One(&merchantDeploy)
|
||||
if err != nil {
|
||||
logs.Error("get merchant deploy by id fail: ", err)
|
||||
}
|
||||
return merchantDeploy
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package order
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rs/xid"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -64,6 +65,15 @@ func InsertOrder(orderInfo OrderInfo) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func HiddenOrder(info *OrderInfo) (bankOrderId string, err error) {
|
||||
bankOrderId = "6666" + xid.New().String()
|
||||
_, err = orm.NewOrm().QueryTable(ORDER_INFO).Filter("id", info.Id).Update(orm.Params{
|
||||
"bank_order_id": bankOrderId,
|
||||
"merchant_order_id": "", // 现有订单id为空
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateIpRestricted 修改IP限制状态
|
||||
func UpdateIpRestricted(orderId string, isIpRestricted bool) bool {
|
||||
o := orm.NewOrm()
|
||||
@@ -268,3 +278,20 @@ func InsertPayTime(merchantOrderId string) bool {
|
||||
})
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func GetByUidAndRoadUid(uid string, roadUid string) (info []*OrderInfo, err error) {
|
||||
o := orm.NewOrm()
|
||||
_, err = o.QueryTable(ORDER_INFO).Filter("merchant_uid", uid).Filter("road_uid", roadUid).Filter("status", "success").All(&info)
|
||||
return
|
||||
}
|
||||
|
||||
// GetByUidAndRoadUidAndTime 根据时间和筛选条件查询
|
||||
func GetByUidAndRoadUidAndTime(uid string, roadUid string, createTime time.Time) (info []*OrderInfo, err error) {
|
||||
o := orm.NewOrm()
|
||||
_, err = o.QueryTable(ORDER_INFO).Filter("merchant_uid", uid).
|
||||
Filter("create_time__gte", createTime).
|
||||
Filter("road_uid", roadUid).
|
||||
Filter("status", "success").
|
||||
All(&info)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ func init() {
|
||||
|
||||
web.Router("/mfcard/notifyV2", &third_party.MFCardV2Impl{}, "*:PayNotify")
|
||||
web.Router("/appleCard/notify", &third_party.AppleCardImpl{}, "*:PayNotify")
|
||||
web.Router("/appleSharkCard/notify", &third_party.AppleCardSharkImpl{}, "*:PayNotify")
|
||||
web.Router("/tMallGame/notify", &third_party.TMAllGameImpl{}, "*:PayNotify")
|
||||
web.Router("/jdCard/notify", &third_party.JDCardImpl{}, "*:PayNotify")
|
||||
web.Router("/walMart/notify", &third_party.WalMartImpl{}, "*:PayNotify")
|
||||
|
||||
107
internal/service/merchant_hidden_config.go
Normal file
107
internal/service/merchant_hidden_config.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"gateway/internal/entities/supplier"
|
||||
"gateway/internal/models/hidden"
|
||||
"gateway/internal/models/merchant_deploy"
|
||||
"gateway/internal/models/order"
|
||||
"github.com/duke-git/lancet/v2/pointer"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
"github.com/mohae/deepcopy"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetOrderHidden 判断当前订单是否偷卡
|
||||
func GetOrderHidden(orderNo *order.OrderInfo) (cfg *hidden.MerchantHiddenConfig) {
|
||||
// 查询当前订单是否处于偷卡的范围
|
||||
configList, err := hidden.GetAllEnabledMerchantHiddenConfig(orderNo.OrderAmount, orderNo.MerchantUid, orderNo.RoadUid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, config := range configList {
|
||||
merchantDeploy := merchant_deploy.GetById(config.MerchantDeployId)
|
||||
if merchantDeploy == nil {
|
||||
continue
|
||||
}
|
||||
record, err2 := hidden.GetOneMerchantHiddenRecordByHiddenConfigId(config.Id)
|
||||
if err2 != nil {
|
||||
continue
|
||||
}
|
||||
//如果是第一次偷卡
|
||||
if record == nil {
|
||||
//查询当前用户所有的订单
|
||||
orderInfos, err := order.GetByUidAndRoadUid(merchantDeploy.MerchantUid, merchantDeploy.SingleRoadUid)
|
||||
if err != nil || len(orderInfos) == 0 {
|
||||
continue
|
||||
}
|
||||
//计算订单金额
|
||||
amountTotal := slice.ReduceBy(orderInfos, 0, func(index int, item *order.OrderInfo, agg int) int {
|
||||
return agg + int(item.FactAmount)
|
||||
})
|
||||
//如果当前金额超过设定金额,并且面额一致,就偷卡
|
||||
if int(amountTotal) > config.Amount && orderNo.FactAmount == float64(config.FaceAmount) {
|
||||
cfg = config
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
//如果是多次偷卡
|
||||
orderInfos, err := order.GetByUidAndRoadUidAndTime(merchantDeploy.MerchantUid, merchantDeploy.SingleRoadUid, record.CreateAt)
|
||||
if err != nil || len(orderInfos) == 0 {
|
||||
continue
|
||||
}
|
||||
//计算订单金额
|
||||
amountTotal := slice.ReduceBy(orderInfos, 0, func(index int, item *order.OrderInfo, agg int) int {
|
||||
return agg + int(item.FactAmount)
|
||||
})
|
||||
//如果当前金额超过设定金额,并且面额一致,就偷卡
|
||||
if int(amountTotal) > config.Amount && orderNo.FactAmount == float64(config.FaceAmount) {
|
||||
cfg = config
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func HiddenBlankOrder(orderInfo *order.OrderInfo, duration int64) (bankOrderId string, err error) {
|
||||
//复制到一个新的对象中
|
||||
newOrderInfo := deepcopy.Copy(*orderInfo).(*order.OrderInfo)
|
||||
// 创建一个新的失败订单
|
||||
newOrderInfo.CreateTime = orderInfo.CreateTime.Add(time.Second * time.Duration(duration))
|
||||
newOrderInfo.UpdateTime = orderInfo.UpdateTime.Add(time.Second * time.Duration(duration))
|
||||
newOrderInfo.ExValue = "{}"
|
||||
order.InsertOrder(*newOrderInfo)
|
||||
// 去掉现有订单的关联数据
|
||||
bankOrderId, err = order.HiddenOrder(orderInfo)
|
||||
return
|
||||
}
|
||||
|
||||
func HiddenErrorOrder(orderInfo *order.OrderInfo, duration int64) (bankOrderId string, err error) {
|
||||
//复制到一个新的对象中
|
||||
newOrderInfo := deepcopy.Copy(*orderInfo).(*order.OrderInfo)
|
||||
// 创建一个新的失败订单
|
||||
newOrderInfo.CreateTime = orderInfo.CreateTime.Add(time.Second * time.Duration(duration))
|
||||
newOrderInfo.UpdateTime = orderInfo.UpdateTime.Add(time.Second * time.Duration(duration))
|
||||
exValue := supplier.RedeemCardInfo{}
|
||||
if err = json.Unmarshal([]byte(newOrderInfo.ExValue), &exValue); err != nil {
|
||||
return
|
||||
}
|
||||
//字符串转数组
|
||||
targetStr := random.RandFromGivenSlice([]string{exValue.Data})
|
||||
if !pointer.IsNil(targetStr) && targetStr != "" {
|
||||
index := slice.IndexOf([]string{exValue.Data}, targetStr)
|
||||
if index != -1 {
|
||||
if validator.IsNumber(targetStr) {
|
||||
// 替换一个其他数字
|
||||
//exValue.Data = random.RandFromGivenSlice([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"})
|
||||
}
|
||||
}
|
||||
}
|
||||
order.InsertOrder(*newOrderInfo)
|
||||
// 去掉现有订单的关联数据
|
||||
bankOrderId, _ = order.HiddenOrder(orderInfo)
|
||||
return
|
||||
}
|
||||
@@ -305,6 +305,7 @@ func GenerateRecord(c *response.PayBaseResp) (order.OrderInfo, order.OrderProfit
|
||||
if c.Code == -1 {
|
||||
return orderInfo, orderProfit, errors.New("订单数据插入失败")
|
||||
}
|
||||
//插入订单记录和订单利润记录
|
||||
if !order.InsertOrderAndOrderProfit(orderInfo, orderProfit) {
|
||||
c.Code = -1
|
||||
return orderInfo, orderProfit, errors.New("订单数据插入失败")
|
||||
|
||||
Reference in New Issue
Block a user