diff --git a/config/configs.go b/config/configs.go index aa06dc6..9b14242 100644 --- a/config/configs.go +++ b/config/configs.go @@ -28,6 +28,7 @@ type Config struct { Database Database `mapstructure:"postgresql"` Jwt Jwt `mapstructure:"jwt"` OSSConfig OSSConfig `mapstructure:"oss"` + Midtrans Midtrans `mapstructure:"midtrans"` } var ( @@ -64,5 +65,7 @@ func (c *Config) Auth() *AuthConfig { return &AuthConfig{ jwtTokenSecret: c.Jwt.Token.Secret, jwtTokenExpiresTTL: c.Jwt.Token.ExpiresTTL, + jwtOrderSecret: c.Jwt.TokenOrder.Secret, + jwtOrderExpiresTTL: c.Jwt.TokenOrder.ExpiresTTL, } } diff --git a/config/crypto.go b/config/crypto.go index d3db86a..c465b70 100644 --- a/config/crypto.go +++ b/config/crypto.go @@ -5,12 +5,23 @@ import "time" type AuthConfig struct { jwtTokenExpiresTTL int jwtTokenSecret string + jwtOrderSecret string + jwtOrderExpiresTTL int } func (c *AuthConfig) AccessTokenSecret() string { return c.jwtTokenSecret } +func (c *AuthConfig) AccessTokenOrderSecret() string { + return c.jwtOrderSecret +} + +func (c *AuthConfig) AccessTokenOrderExpiresDate() time.Time { + duration := time.Duration(c.jwtOrderExpiresTTL) + return time.Now().UTC().Add(time.Minute * duration) +} + func (c *AuthConfig) AccessTokenExpiresDate() time.Time { duration := time.Duration(c.jwtTokenExpiresTTL) return time.Now().UTC().Add(time.Minute * duration) diff --git a/config/jwt.go b/config/jwt.go index aec29b2..a58d2b1 100644 --- a/config/jwt.go +++ b/config/jwt.go @@ -1,7 +1,8 @@ package config type Jwt struct { - Token Token `mapstructure:"token"` + Token Token `mapstructure:"token"` + TokenOrder Token `mapstructure:"token-order"` } type Token struct { diff --git a/config/midtrans.go b/config/midtrans.go new file mode 100644 index 0000000..bddf763 --- /dev/null +++ b/config/midtrans.go @@ -0,0 +1,25 @@ +package config + +type Midtrans struct { + Serverkey string `mapstructure:"server_key"` + Clientkey string `mapstructure:"client_key"` + Env int `mapstructure:"env"` +} + +type MidtransConfig interface { + MidtransServerKey() string + MidtransClientKey() string + MidtranEnvType() int +} + +func (c *Midtrans) MidtransServerKey() string { + return c.Serverkey +} + +func (c *Midtrans) MidtransClientKey() string { + return c.Clientkey +} + +func (c *Midtrans) MidtranEnvType() int { + return c.Env +} diff --git a/go.mod b/go.mod index 9a7281b..011326b 100644 --- a/go.mod +++ b/go.mod @@ -3,29 +3,27 @@ module furtuna-be go 1.19 require ( - github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible github.com/gin-gonic/gin v1.9.1 github.com/go-playground/validator/v10 v10.17.0 github.com/gofrs/uuid v4.2.0+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.1.2 - github.com/hashicorp/go-multierror v1.1.1 - github.com/jackc/pgconn v1.10.1 - github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451 github.com/lib/pq v1.2.0 github.com/spf13/viper v1.16.0 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.2 golang.org/x/crypto v0.18.0 gopkg.in/yaml.v3 v3.0.1 + gorm.io/datatypes v1.2.0 ) require ( github.com/KyleBanks/depth v1.2.1 // indirect - github.com/PuerkitoBio/purell v1.2.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/bytedance/sonic v1.10.2 // indirect + github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -35,15 +33,12 @@ require ( github.com/go-openapi/swag v0.22.8 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.1.1 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.2.0 // indirect + github.com/jackc/pgx/v5 v5.3.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -58,37 +53,29 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect - github.com/swaggo/files v1.0.1 // indirect - github.com/swaggo/gin-swagger v1.6.0 // indirect - github.com/swaggo/swag v1.16.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - github.com/urfave/cli/v2 v2.27.1 // indirect - github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect golang.org/x/arch v0.7.0 // indirect golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.1.0 // indirect golang.org/x/tools v0.17.0 // indirect google.golang.org/protobuf v1.32.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + gorm.io/driver/mysql v1.4.7 // indirect ) require ( github.com/aws/aws-sdk-go v1.50.0 + github.com/veritrans/go-midtrans v0.0.0-20210616100512-16326c5eeb00 go.uber.org/zap v1.21.0 - golang.org/x/net v0.20.0 // indirect - gorm.io/driver/postgres v1.4.6 - gorm.io/gorm v1.24.5 + golang.org/x/net v0.20.0 + gorm.io/driver/postgres v1.5.0 + gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11 ) diff --git a/go.sum b/go.sum index 318a640..a1d8d7f 100644 --- a/go.sum +++ b/go.sum @@ -40,25 +40,18 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28= -github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible h1:6JF1bjhT0WN2srEmijfOFtVWwV91KZ6dJY1/JbdtGrI= -github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aws/aws-sdk-go v1.50.0 h1:HBtrLeO+QyDKnc3t1+5DR1RxodOHCGr8ZcrHudpv7jI= github.com/aws/aws-sdk-go v1.50.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= -github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= @@ -72,12 +65,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -91,14 +78,11 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= -github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -117,19 +101,18 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM= -github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74= github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= -github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -155,7 +138,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -167,9 +149,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -190,59 +170,19 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= -github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451 h1:WAvSpGf7MsFuzAtK4Vk7R4EVe+liW4x83r4oWu0WHKw= -github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v5 v5.2.0 h1:NdPpngX0Y6z6XDFKqmFQaE+bCtkqzvQIOt1wvBlAqs8= -github.com/jackc/pgx/v5 v5.2.0/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= +github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA= +github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -250,6 +190,7 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -258,40 +199,31 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= +github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= 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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -299,8 +231,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -312,19 +242,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= @@ -336,8 +254,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -349,8 +265,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= @@ -363,65 +277,44 @@ github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= 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/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= -github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= -github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI= -github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/veritrans/go-midtrans v0.0.0-20210616100512-16326c5eeb00 h1:iCcVFY2mUdalvtpNN0M/vcf7+OYHGKXwzG5JLZgjwQU= +github.com/veritrans/go-midtrans v0.0.0-20210616100512-16326c5eeb00/go.mod h1:21mwYsDK+z+5kR2fvUB8n2yijZZm504Vjzk1s0rNQJg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= golang.org/x/arch v0.7.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-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -459,6 +352,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -471,7 +365,6 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -494,12 +387,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -523,23 +412,17 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -569,21 +452,13 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -593,20 +468,12 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -614,14 +481,12 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -660,8 +525,6 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -754,9 +617,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -764,23 +624,26 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 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= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.4.6 h1:1FPESNXqIKG5JmraaH2bfCVlMQ7paLoCreFxDtqzwdc= -gorm.io/driver/postgres v1.4.6/go.mod h1:UJChCNLFKeBqQRE+HrkFUbKbq9idPXmTOk2u4Wok8S4= -gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE= -gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco= +gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04= +gorm.io/driver/mysql v1.4.7 h1:rY46lkCspzGHn7+IYsNpSfEv9tA+SU4SkkB+GFX125Y= +gorm.io/driver/mysql v1.4.7/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc= +gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= +gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= +gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= +gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11 h1:9qNbmu21nNThCNnF5i2R3kw2aL27U8ZwbzccNjOmW0g= +gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -793,5 +656,3 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/infra/furtuna.development.yaml b/infra/furtuna.development.yaml index b53ecfe..1ec9530 100644 --- a/infra/furtuna.development.yaml +++ b/infra/furtuna.development.yaml @@ -7,6 +7,9 @@ jwt: token: expires-ttl: 1440 secret: "5Lm25V3Qd7aut8dr4QUxm5PZUrSFs" + token-order: + expires-ttl: 2 + secret: "123Lm25V3Qd7aut8dr4QUxm5PZUrSFs" postgresql: host: 103.96.146.124 @@ -27,4 +30,9 @@ oss: endpoint: obs.eranyacloud.com bucket_name: furtuna-dev log_level: Error # type: LogOff, Debug, Error, Warn, Info - host_url: https://obs.eranyacloud.com \ No newline at end of file + host_url: https://obs.eranyacloud.com + +midtrans: + server_key: "SB-Mid-server-YOIvuaIlRw3In9SymCuFz-hB" + client_key: "SB-Mid-client-ulkZGFiS8PqBNOZz" + env: 1 \ No newline at end of file diff --git a/internal/common/mycontext/kinoscontext.go b/internal/common/mycontext/kinoscontext.go index c3e9ca3..353f9d8 100644 --- a/internal/common/mycontext/kinoscontext.go +++ b/internal/common/mycontext/kinoscontext.go @@ -13,6 +13,7 @@ type Context interface { RequestedBy() int64 IsSuperAdmin() bool + IsCasheer() bool GetPartnerID() *int64 } @@ -33,6 +34,10 @@ func (m *MyContextImpl) IsSuperAdmin() bool { return m.roleID == int(role.SuperAdmin) } +func (m *MyContextImpl) IsCasheer() bool { + return m.roleID == int(role.Casheer) +} + func (m *MyContextImpl) GetPartnerID() *int64 { if m.partnerID != 0 { return &m.partnerID diff --git a/internal/constants/order/order.go b/internal/constants/order/order.go index 97d370d..27c02ba 100644 --- a/internal/constants/order/order.go +++ b/internal/constants/order/order.go @@ -24,6 +24,10 @@ func (i *OrderStatus) IsNew() bool { return false } +func (i OrderStatus) String() string { + return string(i) +} + type ItemType string const ( diff --git a/internal/entity/jwt.go b/internal/entity/jwt.go index 53686a6..44f9061 100644 --- a/internal/entity/jwt.go +++ b/internal/entity/jwt.go @@ -10,3 +10,9 @@ type JWTAuthClaims struct { PartnerID int64 `json:"partner_id"` jwt.StandardClaims } + +type JWTOrderClaims struct { + PartnerID int64 `json:"id"` + OrderID int64 `json:"order_id"` + jwt.StandardClaims +} diff --git a/internal/entity/midtrans.go b/internal/entity/midtrans.go new file mode 100644 index 0000000..b26f0d2 --- /dev/null +++ b/internal/entity/midtrans.go @@ -0,0 +1,12 @@ +package entity + +type MidtransResponse struct { + Token string + RedirectURL string +} + +type MidtransRequest struct { + PaymentReferenceID string + TotalAmount int64 + OrderItems []OrderItem +} diff --git a/internal/entity/order.go b/internal/entity/order.go index 2767882..ca046e0 100644 --- a/internal/entity/order.go +++ b/internal/entity/order.go @@ -1,166 +1,77 @@ package entity import ( - "furtuna-be/internal/constants/order" "time" ) type Order struct { - ID int64 - BranchID int64 - BranchName string - Status order.OrderStatus - Amount float64 - CustomerName string `gorm:"column:customer_name" json:"customer_name"` - CustomerPhone string `gorm:"column:customer_phone" json:"customer_phone"` - Pax int `gorm:"column:pax" json:"pax"` - CreatedAt time.Time - UpdatedAt time.Time - CreatedBy int64 - UpdatedBy int64 - Transaction Transaction - OrderItem []OrderItem + ID int64 `gorm:"primaryKey;autoIncrement;column:id"` + RefID string `gorm:"type:varchar;column:ref_id"` + PartnerID int64 `gorm:"type:int;column:partner_id"` + Status string `gorm:"type:varchar;column:status"` + Amount float64 `gorm:"type:numeric;not null;column:amount"` + CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"` + UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"` + CreatedBy int64 `gorm:"type:int;column:created_by"` + PaymentType string `gorm:"type:varchar;column:payment_type"` + UpdatedBy int64 `gorm:"type:int;column:updated_by"` + OrderItems []OrderItem `gorm:"foreignKey:OrderID;constraint:OnDelete:CASCADE;"` } -type OrderSearch struct { - Search string - StatusActive order.OrderSearchStatus - Status order.OrderStatus - BranchID int64 - Limit int - Offset int +type OrderResponse struct { + Order *Order + Token string } -type OrderTotalRevenueSearch struct { - Year int - Month int - BranchID int64 - DateStart *time.Time - DateEnd *time.Time +type ExecuteOrderResponse struct { + Order *Order + PaymentToken string + RedirectURL string } -type OrderYearlyRevenueList []OrderYearlyRevenue -type OrderYearlyRevenue struct { - ItemType string `gorm:"column:item_type"` - Month int `gorm:"column:month_number"` - Amount float64 `gorm:"column:total_amount"` -} - -type OrderBranchRevenueSearch struct { - DateStart *time.Time - DateEnd *time.Time -} - -type OrderBranchRevenueList []OrderBranchRevenue -type OrderBranchRevenue struct { - BranchID string `gorm:"column:branch_id"` - BranchName string `gorm:"column:name"` - BranchLocation string `gorm:"column:location"` - TotalTransaction int `gorm:"column:total_trans"` - TotalAmount float64 `gorm:"column:total_amount"` -} - -type OrderList []*OrderDB - -type OrderDB struct { - Order -} - -func (b *Order) ToOrderDB() *OrderDB { - var amount float64 - for _, i := range b.OrderItem { - amount = amount + (i.Price * float64(i.Qty)) - } - b.Amount = amount - b.Transaction.Amount = amount - - return &OrderDB{ - Order: *b, - } -} - -func (OrderDB) TableName() string { +func (Order) TableName() string { return "orders" } -func (e *OrderDB) ToOrder() *Order { - return &Order{ - ID: e.ID, - Status: e.Status, - BranchID: e.BranchID, - BranchName: e.BranchName, - Amount: e.Amount, - CustomerName: e.CustomerName, - CustomerPhone: e.CustomerPhone, - Pax: e.Pax, - Transaction: e.Transaction, - OrderItem: e.OrderItem, - CreatedAt: e.CreatedAt, - UpdatedAt: e.UpdatedAt, - CreatedBy: e.CreatedBy, - UpdatedBy: e.UpdatedBy, - } -} - -func (b *OrderList) ToOrderList() []*Order { - var Orders []*Order - for _, order := range *b { - Orders = append(Orders, order.ToOrder()) - } - return Orders -} - -func (o *OrderDB) ToUpdatedOrder(updatedby int64, req Order) { - o.UpdatedBy = updatedby - - if req.Amount > 0 { - o.Amount = req.Amount - } - - if req.Status != "" { - o.Status = req.Status - } -} - type OrderItem struct { - OrderItemID int64 - OrderID int64 - ItemID int64 - ItemType order.ItemType - ItemName string - Price float64 - Qty int64 - CreatedAt time.Time - UpdatedAt time.Time - CreatedBy int64 - UpdatedBy int64 + ID int64 `gorm:"primaryKey;autoIncrement;column:order_item_id"` + OrderID int64 `gorm:"type:int;column:order_id"` + ItemID int64 `gorm:"type:int;column:item_id"` + ItemType string `gorm:"type:varchar;column:item_type"` + Price float64 `gorm:"type:numeric;not null;column:price"` + Quantity int64 `gorm:"type:int;column:qty"` + CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"` + UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"` + CreatedBy int64 `gorm:"type:int;column:created_by"` + UpdatedBy int64 `gorm:"type:int;column:updated_by"` } -type OrderItemDB struct { - OrderItem -} - -func (b *OrderItem) ToOrderItemDB() *OrderItemDB { - return &OrderItemDB{ - OrderItem: *b, - } -} - -func (OrderItemDB) TableName() string { +func (OrderItem) TableName() string { return "order_items" } -func (e *OrderItemDB) ToOrderItem() *OrderItem { - return &OrderItem{ - OrderItemID: e.OrderItemID, - OrderID: e.OrderID, - ItemID: e.ItemID, - ItemType: e.ItemType, - Price: e.Price, - Qty: e.Qty, - CreatedAt: e.CreatedAt, - UpdatedAt: e.UpdatedAt, - CreatedBy: e.CreatedBy, - UpdatedBy: e.UpdatedBy, - } +type OrderRequest struct { + CreatedBy int64 + PartnerID int64 `json:"partner_id" validate:"required"` + PaymentMethod string `json:"payment_method" validate:"required"` + OrderItems []OrderItemRequest `json:"order_items" validate:"required,dive"` +} + +type OrderItemRequest struct { + ProductID int64 `json:"product_id" validate:"required"` + Quantity int64 `json:"quantity" validate:"required"` +} + +type OrderExecuteRequest struct { + CreatedBy int64 + PartnerID int64 + Token string +} + +func (o *Order) SetExecutePaymentStatus() { + if o.PaymentType == "CASH" { + o.Status = "PAID" + return + } + o.Status = "PENDING" } diff --git a/internal/entity/payment.go b/internal/entity/payment.go new file mode 100644 index 0000000..9cc1acb --- /dev/null +++ b/internal/entity/payment.go @@ -0,0 +1,26 @@ +package entity + +import ( + "github.com/google/uuid" + "gorm.io/datatypes" + "time" +) + +type Payment struct { + ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4();primaryKey;column:id"` + PartnerID string `gorm:"type:varchar;not null;column:partner_id"` + OrderID string `gorm:"type:varchar;not null;column:order_id"` + ReferenceID string `gorm:"type:varchar;not null;column:reference_id"` + Channel string `gorm:"type:varchar;not null;column:channel"` + PaymentType string `gorm:"type:varchar;not null;column:payment_type"` + Amount float64 `gorm:"type:numeric;not null;column:amount"` + State string `gorm:"type:varchar;not null;column:state"` + RequestMetadata datatypes.JSON `gorm:"type:json;not null;column:request_metadata"` + CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"` + UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"` + FinishedAt time.Time `gorm:"column:finished_at"` +} + +func (Payment) TableName() string { + return "payments" +} diff --git a/internal/entity/transaction.go b/internal/entity/transaction.go index bd76d90..9debf98 100644 --- a/internal/entity/transaction.go +++ b/internal/entity/transaction.go @@ -7,7 +7,7 @@ import ( type Transaction struct { ID int64 - BranchID int64 + PartnerID int64 Status transaction.PaymentStatus Amount float64 OrderID int64 diff --git a/internal/handlers/http/order/order.go b/internal/handlers/http/order/order.go index a6ad9e1..92e23ec 100644 --- a/internal/handlers/http/order/order.go +++ b/internal/handlers/http/order/order.go @@ -6,12 +6,9 @@ import ( "furtuna-be/internal/handlers/request" "furtuna-be/internal/handlers/response" "furtuna-be/internal/services" - "net/http" - "strconv" - "time" - "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" + "net/http" ) type Handler struct { @@ -21,13 +18,8 @@ type Handler struct { func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) { route := group.Group("/order") - route.POST("/", jwt, h.Create) - route.GET("/list", jwt, h.GetAll) - route.GET("/:id", jwt, h.GetByID) - route.GET("/total-revenue", jwt, h.GetTotalRevenue) - route.GET("/yearly-revenue/:year", jwt, h.GetYearlyRevenue) - route.GET("/branch-revenue", jwt, h.GetBranchRevenue) - route.PUT("/update-status/:id", jwt, h.UpdateStatus) + route.POST("/inquiry", jwt, h.Inquiry) + route.POST("/execute", jwt, h.Execute) } func NewHandler(service services.Order) *Handler { @@ -36,19 +28,7 @@ func NewHandler(service services.Order) *Handler { } } -// Create handles the creation of a new order. -// @Summary Create a new order -// @Description Create a new order with the provided details. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param order body request.Order true "Order details" -// @Success 200 {object} response.BaseResponse "Order created successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Router /api/v1/order [post] -// @Tag Order APIs -func (h *Handler) Create(c *gin.Context) { +func (h *Handler) Inquiry(c *gin.Context) { ctx := request.GetMyContext(c) var req request.Order @@ -57,14 +37,21 @@ func (h *Handler) Create(c *gin.Context) { return } + if !ctx.IsCasheer() { + response.ErrorWrapper(c, errors.ErrorBadRequest) + return + } + + // override the partner_id + req.PartnerID = *ctx.GetPartnerID() + validate := validator.New() if err := validate.Struct(req); err != nil { response.ErrorWrapper(c, err) return } - err := h.service.Create(ctx, req.ToEntity()) - + order, err := h.service.CreateOrder(ctx, req.ToEntity(ctx.RequestedBy())) if err != nil { response.ErrorWrapper(c, err) return @@ -73,122 +60,33 @@ func (h *Handler) Create(c *gin.Context) { c.JSON(http.StatusOK, response.BaseResponse{ Success: true, Status: http.StatusOK, + Data: MapOrderToCreateOrderResponse(order), }) } -// UpdateStatus handles the update of the order status. -// @Summary Update the status of an order -// @Description Update the status of the specified order with the provided details. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param id path string true "Order ID" -// @Param status body request.UpdateStatus true "Status details" -// @Success 200 {object} response.BaseResponse{data=response.Order} "Order status updated successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Failure 500 {object} response.BaseResponse "Internal server error" -// @Router /api/v1/order/update-status/{id} [put] -// @Tag Order APIs -func (h *Handler) UpdateStatus(c *gin.Context) { +func (h *Handler) Execute(c *gin.Context) { ctx := request.GetMyContext(c) - var req request.UpdateStatus + var req request.Execute if err := c.ShouldBindJSON(&req); err != nil { response.ErrorWrapper(c, errors.ErrorBadRequest) return } - id := c.Param("id") - - // Parse the ID into a uint - orderID, err := strconv.ParseInt(id, 10, 64) - if err != nil { + if !ctx.IsCasheer() { response.ErrorWrapper(c, errors.ErrorBadRequest) return } - res, err := h.service.UpdateStatus(ctx, orderID, req.ToEntity()) - if err != nil { - c.JSON(http.StatusInternalServerError, response.BaseResponse{ - Success: false, - Status: http.StatusInternalServerError, - Message: err.Error(), - Data: nil, - }) + req.PartnerID = *ctx.GetPartnerID() + + validate := validator.New() + if err := validate.Struct(req); err != nil { + response.ErrorWrapper(c, err) return } - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toOrderResponse(res), - }) -} - -// GetByID retrieves the details of a specific order by ID. -// @Summary Get details of an order by ID -// @Description Retrieve the details of the specified order by ID. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param id path string true "Order ID" -// @Success 200 {object} response.BaseResponse{data=response.Order} "Order details retrieved successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Failure 500 {object} response.BaseResponse "Internal server error" -// @Router /api/v1/order/{id} [get] -// @Tag Order APIs -func (h *Handler) GetByID(c *gin.Context) { - id := c.Param("id") - - // Parse the ID into a uint - orderID, err := strconv.ParseInt(id, 10, 64) - if err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - res, err := h.service.GetByID(c.Request.Context(), orderID) - if err != nil { - c.JSON(http.StatusInternalServerError, response.BaseResponse{ - Success: false, - Status: http.StatusInternalServerError, - Message: err.Error(), - Data: nil, - }) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toOrderResponse(res), - }) -} - -// GetAll retrieves a list of orders based on the specified parameters. -// @Summary Get a list of orders -// @Description Retrieve a list of orders based on the specified parameters. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param limit query int false "Number of items to retrieve (default: 10)" -// @Param offset query int false "Number of items to skip (default: 0)" -// @Success 200 {object} response.BaseResponse{data=response.OrderList} "List of orders retrieved successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Failure 500 {object} response.BaseResponse "Internal server error" -// @Router /api/v1/order/list [get] -// @Tag Order APIs -func (h *Handler) GetAll(c *gin.Context) { - var req request.OrderParam - if err := c.ShouldBindQuery(&req); err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - orders, total, err := h.service.GetAll(c.Request.Context(), req.ToEntity()) + order, err := h.service.Execute(ctx, req.ToOrderExecuteRequest(ctx.RequestedBy())) if err != nil { response.ErrorWrapper(c, err) return @@ -197,213 +95,57 @@ func (h *Handler) GetAll(c *gin.Context) { c.JSON(http.StatusOK, response.BaseResponse{ Success: true, Status: http.StatusOK, - Data: h.toOrderResponseList(orders, int64(total), req), + Data: MapOrderToExecuteOrderResponse(order), }) } -// GetTotalRevenue retrieves the total revenue and number of transactions for orders. -// @Summary Get total revenue and number of transactions for orders -// @Description Retrieve the total revenue and number of transactions for orders based on the specified parameters. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param start_date query string false "Start date for filtering (format: 'YYYY-MM-DD')" -// @Param end_date query string false "End date for filtering (format: 'YYYY-MM-DD')" -// @Success 200 {object} response.BaseResponse{data=response.OrderMonthlyRevenue} "Total revenue and transactions retrieved successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Failure 500 {object} response.BaseResponse "Internal server error" -// @Router /api/v1/order/total-revenue [get] -// @Tag Order APIs -func (h *Handler) GetTotalRevenue(c *gin.Context) { - var req request.OrderTotalRevenueParam - if err := c.ShouldBindQuery(&req); err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - rev, trans, err := h.service.GetTotalRevenue(c.Request.Context(), req.ToEntity()) - if err != nil { - c.JSON(http.StatusInternalServerError, response.BaseResponse{ - Success: false, - Status: http.StatusInternalServerError, - Message: err.Error(), - Data: nil, - }) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toOrderTotalRevenueResponse(rev, trans), - }) -} - -// GetYearlyRevenue retrieves the yearly revenue for orders. -// @Summary Get yearly revenue for orders -// @Description Retrieve the yearly revenue for orders based on the specified year. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param year path int true "Year for filtering" -// @Success 200 {object} response.BaseResponse{data=map[int]map[string]float64} "Yearly revenue retrieved successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Failure 500 {object} response.BaseResponse "Internal server error" -// @Router /api/v1/order/yearly-revenue/{year} [get] -// @Tag Order APIs -func (h *Handler) GetYearlyRevenue(c *gin.Context) { - yearParam := c.Param("year") - - // Parse the ID into a uint - year, err := strconv.Atoi(yearParam) - if err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - rev, err := h.service.GetYearlyRevenue(c.Request.Context(), year) - if err != nil { - c.JSON(http.StatusInternalServerError, response.BaseResponse{ - Success: false, - Status: http.StatusInternalServerError, - Message: err.Error(), - Data: nil, - }) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toOrderYearlyRevenueResponse(rev), - }) -} - -// GetBranchRevenue retrieves the branch-wise revenue for orders. -// @Summary Get branch-wise revenue for orders -// @Description Retrieve the branch-wise revenue for orders based on the specified parameters. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param branch_id query int false "Branch ID for filtering" -// @Param start_date query string false "Start date for filtering (format: 'YYYY-MM-DD')" -// @Param end_date query string false "End date for filtering (format: 'YYYY-MM-DD')" -// @Success 200 {object} response.BaseResponse{data=[]response.OrderBranchRevenue} "Branch-wise revenue retrieved successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Failure 500 {object} response.BaseResponse "Internal server error" -// @Router /api/v1/order/branch-revenue [get] -// @Tag Order APIs -func (h *Handler) GetBranchRevenue(c *gin.Context) { - var req request.OrderBranchRevenueParam - if err := c.ShouldBindQuery(&req); err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - rev, err := h.service.GetBranchRevenue(c.Request.Context(), req.ToEntity()) - if err != nil { - c.JSON(http.StatusInternalServerError, response.BaseResponse{ - Success: false, - Status: http.StatusInternalServerError, - Message: err.Error(), - Data: nil, - }) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toOrderBranchRevenueResponse(rev), - }) -} - -func (h *Handler) toOrderResponse(resp *entity.Order) response.Order { - orderItems := []response.OrderItem{} - for _, i := range resp.OrderItem { - orderItems = append(orderItems, response.OrderItem{ - OrderItemID: i.OrderItemID, - ItemID: i.ItemID, - ItemType: i.ItemType, - ItemName: i.ItemName, - Price: i.Price, - Qty: i.Qty, - CreatedAt: i.CreatedAt.Format(time.RFC3339), - UpdatedAt: i.CreatedAt.Format(time.RFC3339), - }) - } - - return response.Order{ - ID: resp.ID, - BranchID: resp.BranchID, - BranchName: resp.BranchName, - Amount: resp.Amount, - OrderItem: orderItems, - Status: resp.Status, - CustomerName: resp.CustomerName, - CustomerPhone: resp.CustomerPhone, - Pax: resp.Pax, - PaymentMethod: resp.Transaction.PaymentMethod, - CreatedAt: resp.CreatedAt.Format(time.RFC3339), - UpdatedAt: resp.CreatedAt.Format(time.RFC3339), - } -} - -func (h *Handler) toOrderResponseList(resp []*entity.Order, total int64, req request.OrderParam) response.OrderList { - var orders []response.Order - for _, b := range resp { - orders = append(orders, h.toOrderResponse(b)) - } - - return response.OrderList{ - Orders: orders, - Total: total, - Limit: req.Limit, - Offset: req.Offset, - } -} - -func (h *Handler) toOrderTotalRevenueResponse(rev float64, trans int64) response.OrderMonthlyRevenue { - return response.OrderMonthlyRevenue{ - TotalRevenue: rev, - TotalTransaction: trans, - } -} - -func (h *Handler) toOrderYearlyRevenueResponse(data entity.OrderYearlyRevenueList) map[int]map[string]float64 { - result := make(map[int]map[string]float64) - - // Initialize result map with 0 values for all months and item types - for i := 1; i <= 12; i++ { - result[i] = map[string]float64{ - "PRODUCT": 0, - "STUDIO": 0, +func MapOrderToCreateOrderResponse(orderResponse *entity.OrderResponse) response.CreateOrderResponse { + order := orderResponse.Order + orderItems := make([]response.CreateOrderItemResponse, len(order.OrderItems)) + for i, item := range order.OrderItems { + orderItems[i] = response.CreateOrderItemResponse{ + ID: item.ID, + ItemID: item.ItemID, + Quantity: item.Quantity, + Price: item.Price, } } - // Populate result map with actual data - for _, v := range data { - result[v.Month][v.ItemType] = v.Amount + return response.CreateOrderResponse{ + ID: order.ID, + RefID: order.RefID, + PartnerID: order.PartnerID, + Status: order.Status, + Amount: order.Amount, + PaymentType: order.PaymentType, + CreatedAt: order.CreatedAt, + OrderItems: orderItems, + Token: orderResponse.Token, } - - return result } -func (h *Handler) toOrderBranchRevenueResponse(data entity.OrderBranchRevenueList) []response.OrderBranchRevenue { - var resp []response.OrderBranchRevenue - - for _, v := range data { - resp = append(resp, response.OrderBranchRevenue{ - BranchID: v.BranchID, - BranchName: v.BranchName, - BranchLocation: v.BranchLocation, - TotalTransaction: v.TotalTransaction, - TotalAmount: v.TotalAmount, - }) +func MapOrderToExecuteOrderResponse(orderResponse *entity.ExecuteOrderResponse) response.ExecuteOrderResponse { + order := orderResponse.Order + orderItems := make([]response.CreateOrderItemResponse, len(order.OrderItems)) + for i, item := range order.OrderItems { + orderItems[i] = response.CreateOrderItemResponse{ + ID: item.ID, + ItemID: item.ItemID, + Quantity: item.Quantity, + Price: item.Price, + } } - return resp + return response.ExecuteOrderResponse{ + ID: order.ID, + RefID: order.RefID, + PartnerID: order.PartnerID, + Status: order.Status, + Amount: order.Amount, + PaymentType: order.PaymentType, + CreatedAt: order.CreatedAt, + OrderItems: orderItems, + PaymentToken: orderResponse.PaymentToken, + RedirectURL: orderResponse.RedirectURL, + } } diff --git a/internal/handlers/http/user/user.go b/internal/handlers/http/user/user.go index bd97716..9d500b7 100644 --- a/internal/handlers/http/user/user.go +++ b/internal/handlers/http/user/user.go @@ -56,14 +56,14 @@ func (h *Handler) Create(c *gin.Context) { return } - req.PartnerID = ctx.GetPartnerID() - if err := req.Validate(); err != nil { - response.ErrorWrapper(c, errors.ErrorInvalidRequest) - return + if !ctx.IsSuperAdmin() { + req.PartnerID = ctx.GetPartnerID() + if err := req.Validate(); err != nil { + response.ErrorWrapper(c, errors.ErrorInvalidRequest) + return + } } - ctx.IsSuperAdmin() - res, err := h.service.Create(ctx, req.ToEntity()) if err != nil { response.ErrorWrapper(c, err) diff --git a/internal/handlers/request/order.go b/internal/handlers/request/order.go index b525e58..ed653a7 100644 --- a/internal/handlers/request/order.go +++ b/internal/handlers/request/order.go @@ -1,116 +1,47 @@ package request import ( - "furtuna-be/internal/constants/order" "furtuna-be/internal/constants/transaction" "furtuna-be/internal/entity" - "time" ) type Order struct { - BranchID int64 `json:"branch_id" validate:"required"` - Amount float64 `json:"amount" validate:"required"` - CustomerName string `json:"customer_name" validate:"required"` - CustomerPhone string `json:"customer_phone" validate:"required"` - Pax int `json:"pax" validate:"required"` + PartnerID int64 `json:"partner_id" validate:"required"` PaymentMethod transaction.PaymentMethod `json:"payment_method" validate:"required"` - OrderItem []OrderItem `json:"order_items" validate:"required"` + OrderItems []OrderItem `json:"order_items" validate:"required"` } type OrderItem struct { - ItemID int64 `json:"item_id" validate:"required"` - ItemType order.ItemType `json:"item_type" validate:"required"` - Price float64 `json:"price" validate:"required"` - Qty int64 `json:"qty" validate:"required"` + ProductID int64 `json:"product_id" validate:"required"` + Quantity int64 `json:"quantity" validate:"required"` } -type OrderParam struct { - Search string `form:"search" json:"search" example:"name,branch_name,item_name"` - StatusActive order.OrderSearchStatus `form:"status_active" json:"status_active" example:"active,inactive"` - Status order.OrderStatus `form:"status" json:"status" example:"NEW,PAID,CANCEL"` - BranchID int64 `form:"branch_id" json:"branch_id" example:"1"` - Limit int `form:"limit" json:"limit" example:"10"` - Offset int `form:"offset" json:"offset" example:"0"` -} - -func (p *OrderParam) ToEntity() entity.OrderSearch { - return entity.OrderSearch{ - Search: p.Search, - StatusActive: p.StatusActive, - Status: p.Status, - BranchID: p.BranchID, - Limit: p.Limit, - Offset: p.Offset, - } -} - -func (o *Order) ToEntity() *entity.Order { - var ordItems []entity.OrderItem - if len(o.OrderItem) > 0 { - for _, i := range o.OrderItem { - ordItems = append(ordItems, entity.OrderItem{ - ItemID: i.ItemID, - ItemType: i.ItemType, - Price: i.Price, - Qty: i.Qty, - }) +func (o *Order) ToEntity(createdBy int64) *entity.OrderRequest { + orderItems := make([]entity.OrderItemRequest, len(o.OrderItems)) + for i, item := range o.OrderItems { + orderItems[i] = entity.OrderItemRequest{ + ProductID: item.ProductID, + Quantity: item.Quantity, } } - transaction := entity.Transaction{ - BranchID: o.BranchID, - CustomerName: o.CustomerName, - CustomerPhone: o.CustomerPhone, - PaymentMethod: o.PaymentMethod, - } - - return &entity.Order{ - BranchID: o.BranchID, - Amount: o.Amount, - CustomerName: o.CustomerName, - CustomerPhone: o.CustomerPhone, - Pax: o.Pax, - Transaction: transaction, - OrderItem: ordItems, + return &entity.OrderRequest{ + PartnerID: o.PartnerID, + PaymentMethod: string(o.PaymentMethod), + OrderItems: orderItems, + CreatedBy: createdBy, } } -type OrderTotalRevenueParam struct { - Year int `form:"year" json:"year" example:"1,2,3"` - Month int `form:"month" json:"month" example:"1,2,3"` - BranchID int64 `form:"branch_id" json:"branch_id" example:"1"` - DateStart *time.Time `form:"date_start" json:"date_start" example:"2024-01-01" time_format:"2006-1-2"` - DateEnd *time.Time `form:"date_end" json:"date_end" example:"2024-01-01" time_format:"2006-1-2"` +type Execute struct { + PartnerID int64 `json:"partner_id" validate:"required"` + Token string `json:"token"` } -func (p *OrderTotalRevenueParam) ToEntity() entity.OrderTotalRevenueSearch { - return entity.OrderTotalRevenueSearch{ - Year: p.Year, - Month: p.Month, - BranchID: p.BranchID, - DateStart: p.DateStart, - DateEnd: p.DateEnd, - } -} - -type OrderBranchRevenueParam struct { - DateStart *time.Time `form:"date_start" json:"date_start" example:"2024-01-01" time_format:"2006-1-2"` - DateEnd *time.Time `form:"date_end" json:"date_end" example:"2024-01-01" time_format:"2006-1-2"` -} - -func (p *OrderBranchRevenueParam) ToEntity() entity.OrderBranchRevenueSearch { - return entity.OrderBranchRevenueSearch{ - DateStart: p.DateStart, - DateEnd: p.DateEnd, - } -} - -type UpdateStatus struct { - Status order.OrderStatus `form:"status" json:"status" example:"NEW,PAID,CANCEL"` -} - -func (o *UpdateStatus) ToEntity() *entity.Order { - return &entity.Order{ - Status: o.Status, +func (e Execute) ToOrderExecuteRequest(createdBy int64) *entity.OrderExecuteRequest { + return &entity.OrderExecuteRequest{ + CreatedBy: createdBy, + PartnerID: e.PartnerID, + Token: e.Token, } } diff --git a/internal/handlers/response/order.go b/internal/handlers/response/order.go index ccd2ef8..6fceeb3 100644 --- a/internal/handlers/response/order.go +++ b/internal/handlers/response/order.go @@ -3,6 +3,7 @@ package response import ( "furtuna-be/internal/constants/order" "furtuna-be/internal/constants/transaction" + "time" ) type Order struct { @@ -50,3 +51,35 @@ type OrderBranchRevenue struct { TotalTransaction int `json:"total_trans"` TotalAmount float64 `json:"total_amount"` } + +type CreateOrderResponse struct { + ID int64 `json:"id"` + RefID string `json:"ref_id"` + PartnerID int64 `json:"partner_id"` + Status string `json:"status"` + Amount float64 `json:"amount"` + PaymentType string `json:"payment_type"` + CreatedAt time.Time `json:"created_at"` + OrderItems []CreateOrderItemResponse `json:"order_items"` + Token string `json:"token"` +} + +type ExecuteOrderResponse struct { + ID int64 `json:"id"` + RefID string `json:"ref_id"` + PartnerID int64 `json:"partner_id"` + Status string `json:"status"` + Amount float64 `json:"amount"` + PaymentType string `json:"payment_type"` + CreatedAt time.Time `json:"created_at"` + OrderItems []CreateOrderItemResponse `json:"order_items"` + PaymentToken string `json:"payment_token"` + RedirectURL string `json:"redirect_url"` +} + +type CreateOrderItemResponse struct { + ID int64 `json:"id"` + ItemID int64 `json:"item_id"` + Quantity int64 `json:"quantity"` + Price float64 `json:"price"` +} diff --git a/internal/repository/crypto/init.go b/internal/repository/crypto/init.go index c5cd4cf..4f310b9 100644 --- a/internal/repository/crypto/init.go +++ b/internal/repository/crypto/init.go @@ -20,6 +20,8 @@ func NewCrypto(config CryptoConfig) *CryptoImpl { type CryptoConfig interface { AccessTokenSecret() string + AccessTokenOrderSecret() string + AccessTokenOrderExpiresDate() time.Time AccessTokenExpiresDate() time.Time } @@ -88,3 +90,46 @@ func (c *CryptoImpl) ParseAndValidateJWT(tokenString string) (*entity.JWTAuthCla return nil, errors.ErrorUnauthorized } } + +func (c *CryptoImpl) GenerateJWTOrder(order *entity.Order) (string, error) { + claims := &entity.JWTOrderClaims{ + StandardClaims: jwt.StandardClaims{ + Subject: strconv.FormatInt(order.ID, 10), + ExpiresAt: c.Config.AccessTokenOrderExpiresDate().Unix(), + IssuedAt: time.Now().Unix(), + NotBefore: time.Now().Unix(), + }, + PartnerID: order.PartnerID, + OrderID: order.ID, + } + + token, err := jwt. + NewWithClaims(jwt.SigningMethodHS256, claims). + SignedString([]byte(c.Config.AccessTokenOrderSecret())) + + if err != nil { + return "", err + } + + return token, nil +} + +func (c *CryptoImpl) ValidateJWTOrder(tokenString string) (int64, int64, error) { + token, err := jwt.ParseWithClaims(tokenString, &entity.JWTOrderClaims{}, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + return []byte(c.Config.AccessTokenOrderSecret()), nil + }) + + if err != nil { + return 0, 0, err + } + + claims, ok := token.Claims.(*entity.JWTOrderClaims) + if !ok || !token.Valid { + return 0, 0, fmt.Errorf("invalid token %v", token.Header["alg"]) + } + + return claims.PartnerID, claims.OrderID, nil +} diff --git a/internal/repository/midtrans/init.go b/internal/repository/midtrans/init.go new file mode 100644 index 0000000..253e612 --- /dev/null +++ b/internal/repository/midtrans/init.go @@ -0,0 +1,81 @@ +package mdtrns + +import ( + "fmt" + "furtuna-be/internal/common/logger" + "furtuna-be/internal/entity" + "log" + "strconv" + + "github.com/veritrans/go-midtrans" +) + +type MidtransConfig interface { + MidtransServerKey() string + MidtransClientKey() string + MidtranEnvType() int +} + +type ClientService struct { + client midtrans.Client + midtransConfig MidtransConfig +} + +func New(midtransConfig MidtransConfig) *ClientService { + midclient := midtrans.NewClient() + midclient.ServerKey = midtransConfig.MidtransServerKey() + midclient.ClientKey = midtransConfig.MidtransClientKey() + midclient.APIEnvType = midtrans.EnvironmentType(midtransConfig.MidtranEnvType()) + + return &ClientService{ + client: midclient, + midtransConfig: midtransConfig, + } +} + +func (c *ClientService) CreatePayment(order entity.MidtransRequest) (*entity.MidtransResponse, error) { + var snapGateway midtrans.SnapGateway + snapGateway = midtrans.SnapGateway{ + Client: c.client, + } + + snapReq := &midtrans.SnapReq{ + EnabledPayments: []midtrans.PaymentType{ + midtrans.SourceGopay, + }, + TransactionDetails: midtrans.TransactionDetails{ + OrderID: order.PaymentReferenceID, + GrossAmt: order.TotalAmount, + }, + } + + log.Println("GetToken:") + snapTokenResp, err := snapGateway.GetToken(snapReq) + + if err != nil { + logger.GetLogger().Error(fmt.Sprintf("error when create midtrans payment %v", err)) + return nil, err + } + + return &entity.MidtransResponse{ + Token: snapTokenResp.Token, + RedirectURL: snapTokenResp.RedirectURL, + }, nil + +} + +func (c ClientService) getProductItems(products []entity.OrderItem) []midtrans.ItemDetail { + var items []midtrans.ItemDetail + + for _, product := range products { + item := midtrans.ItemDetail{ + ID: strconv.FormatInt(product.ID, 10), + Name: product.ItemType, + Qty: int32(product.Quantity), + Price: int64(product.Price), + } + items = append(items, item) + } + + return items +} diff --git a/internal/repository/orders/order.go b/internal/repository/orders/order.go index d514eb5..319ace5 100644 --- a/internal/repository/orders/order.go +++ b/internal/repository/orders/order.go @@ -2,10 +2,8 @@ package orders import ( "context" - "fmt" "furtuna-be/internal/common/logger" "furtuna-be/internal/entity" - "go.uber.org/zap" "gorm.io/gorm" ) @@ -20,284 +18,42 @@ func NewOrderRepository(db *gorm.DB) *OrderRepository { } } -func (o *OrderRepository) CreateOrder(ctx context.Context, order *entity.OrderDB) (*entity.OrderDB, error) { - tx := o.db.Begin() - - if err := tx.Select("branch_id", "status", "customer_name", "customer_phone", "pax", "amount", "created_by").Create(order).Error; err != nil { - tx.Rollback() - logError(ctx, "creating order", err) +func (r *OrderRepository) Create(ctx context.Context, order *entity.Order) (*entity.Order, error) { + err := r.db.WithContext(ctx).Create(order).Error + if err != nil { + logger.ContextLogger(ctx).Error("error when creating order", zap.Error(err)) return nil, err } - - for i, orditem := range order.OrderItem { - orderItem := orditem.ToOrderItemDB() - orderItem.OrderID = order.ID - - err := tx.Select("order_id", "item_id", "item_type", "price", "qty", "created_by").Create(orderItem).Error - if err != nil { - logger.ContextLogger(ctx).Error("error when create order item", zap.Error(err)) - return nil, err - } - - order.OrderItem[i] = *orderItem.ToOrderItem() - } - - //insert transaction - transaction := order.Transaction.ToTransactionDB() - transaction.OrderID = order.ID - - if err := tx.Select("branch_id", "status", "amount", "order_id", "payment_method", "customer_name", "customer_phone", "created_by").Create(transaction).Error; err != nil { - tx.Rollback() - logError(ctx, "creating transaction", err) - return nil, err - } - - if err := tx.Commit().Error; err != nil { - tx.Rollback() - logError(ctx, "committing transaction", err) - return nil, err - } - return order, nil } -func (b *OrderRepository) UpdateOrder(ctx context.Context, order *entity.OrderDB) (*entity.OrderDB, error) { - - if err := b.db.Select("status", "updated_at", "updated_by").Save(order).Error; err != nil { - logError(ctx, "update order", err) +func (r *OrderRepository) UpdateStatus(ctx context.Context, orderID int64, status string) (*entity.Order, error) { + order := new(entity.Order) + if err := r.db.WithContext(ctx).First(order, orderID).Error; err != nil { + logger.ContextLogger(ctx).Error("error when finding order", zap.Error(err)) + return nil, err + } + order.Status = status + if err := r.db.WithContext(ctx).Save(order).Error; err != nil { + logger.ContextLogger(ctx).Error("error when updating order status", zap.Error(err)) return nil, err } - return order, nil } -func (b *OrderRepository) GetAllOrders(ctx context.Context, req entity.OrderSearch) (entity.OrderList, int, error) { - var orders []*entity.OrderDB - var total int64 - - query := b.db.Table("orders"). - Select("orders.id, orders.branch_id, b.name as branch_name, orders.status, orders.amount, orders.created_at, orders.updated_at, oi.order_item_id, oi.order_id, oi.item_id, oi.item_type, COALESCE(p.name, s.name, '') as item_name, oi.price, oi.qty, oi.created_at, oi.updated_at, COALESCE(t.payment_method, ''), COALESCE(orders.customer_name, ''), COALESCE(orders.customer_phone, ''), COALESCE(orders.pax, 0)"). - Joins("LEFT JOIN order_items oi ON orders.id = oi.order_id"). - Joins("LEFT JOIN transactions t ON orders.id = t.order_id"). - Joins("LEFT JOIN products p ON oi.item_id = p.id AND oi.item_type ='PRODUCT' "). - Joins("LEFT JOIN studios s ON oi.item_id = s.id AND oi.item_type ='STUDIO' "). - Joins("LEFT JOIN branches b ON orders.branch_id = b.id") - - if req.Search != "" { - query = query.Where("b.name ILIKE ? or orders.status ILIKE ? or oi.item_type ILIKE ? or p.name ILIKE ? or orders.customer_name ILIKE ? ", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%") - } - - if req.Status != "" { - query = query.Where("orders.status = ?", req.Status) - } - - if req.BranchID > 0 { - query = query.Where("orders.branch_id = ?", req.BranchID) - } - - if req.StatusActive.IsActive() { - query = query.Joins("INNER JOIN (SELECT o.id, oi.qty, o.created_at FROM orders o INNER JOIN order_items oi ON o.id = oi.order_id AND oi.item_type = 'STUDIO' where o.status != 'CANCEL' and CURRENT_TIMESTAMP > o.created_at AND CURRENT_TIMESTAMP < (o.created_at + (oi.qty || ' hours')::interval)) order_active on order_active.id=orders.id") - } - - if req.Limit > 0 { - query = query.Limit(req.Limit) - } - - if req.Offset > 0 { - query = query.Offset(req.Offset) - } - - query.Order("orders.created_at DESC") - - rows, err := query.Rows() - if err != nil { - return nil, 0, err - } - - defer rows.Close() - - ordersMap := make(map[int64]*entity.OrderDB) // Map to store orders by ID - for rows.Next() { - var ordr entity.OrderDB - var oi entity.OrderItem - - err := rows.Scan(&ordr.ID, &ordr.BranchID, &ordr.BranchName, &ordr.Status, &ordr.Amount, &ordr.CreatedAt, &ordr.UpdatedAt, - &oi.OrderItemID, &oi.OrderID, &oi.ItemID, &oi.ItemType, &oi.ItemName, &oi.Price, &oi.Qty, &oi.CreatedAt, &oi.UpdatedAt, - &ordr.Transaction.PaymentMethod, &ordr.CustomerName, &ordr.CustomerPhone, &ordr.Pax) - if err != nil { - logger.ContextLogger(ctx).Error("error scanning rows", zap.Error(err)) - return nil, 0, err - } - - if order, ok := ordersMap[ordr.ID]; ok { - // Order already exists in map, append OrderItem to existing order - order.OrderItem = append(order.OrderItem, oi) - } else { - // Order doesn't exist in map, create a new OrderDB - newOrder := ordr - newOrder.OrderItem = []entity.OrderItem{oi} - ordersMap[ordr.ID] = &newOrder - - orders = append(orders, &ordr) - } - } - - // assign value order item - for _, v := range orders { - v.OrderItem = ordersMap[v.ID].OrderItem - } - - //reset limit for count total data - query = query.Offset(-1).Limit(-1) - - if err := query.Count(&total).Error; err != nil { - logger.ContextLogger(ctx).Error("error when count orders", zap.Error(err)) - return nil, 0, err - } - - return orders, int(total), nil -} - -func (b *OrderRepository) GetOrderByID(ctx context.Context, id int64) (*entity.OrderDB, error) { - var orders *entity.OrderDB - - query := b.db.Table("orders"). - Select("orders.id, orders.branch_id, b.name as branch_name, orders.status, orders.amount, orders.created_at, orders.updated_at, oi.order_item_id, oi.order_id, oi.item_id, oi.item_type, COALESCE(p.name, s.name, '') as item_name, oi.price, oi.qty, oi.created_at, oi.updated_at, t.payment_method, orders.customer_name, orders.customer_phone, orders.pax"). - Joins("LEFT JOIN order_items oi ON orders.id = oi.order_id"). - Joins("LEFT JOIN transactions t ON orders.id = t.order_id"). - Joins("LEFT JOIN products p ON oi.item_id = p.id AND oi.item_type ='PRODUCT' "). - Joins("LEFT JOIN studios s ON oi.item_id = s.id AND oi.item_type ='STUDIO' "). - Joins("LEFT JOIN branches b ON orders.branch_id = b.id"). - Where("orders.id = ?", id) - - rows, err := query.Rows() - if err != nil { +func (r *OrderRepository) FindByID(ctx context.Context, id int64) (*entity.Order, error) { + var order entity.Order + if err := r.db.WithContext(ctx).Preload("OrderItems").First(&order, id).Error; err != nil { + logger.ContextLogger(ctx).Error("error when finding order by ID", zap.Error(err)) return nil, err } - - defer rows.Close() - - var ordr entity.OrderDB // Map to store orders by ID - for rows.Next() { - var oi entity.OrderItem - - err := rows.Scan(&ordr.ID, &ordr.BranchID, &ordr.BranchName, &ordr.Status, &ordr.Amount, &ordr.CreatedAt, &ordr.UpdatedAt, - &oi.OrderItemID, &oi.OrderID, &oi.ItemID, &oi.ItemType, &oi.ItemName, &oi.Price, &oi.Qty, &oi.CreatedAt, &oi.UpdatedAt, - &ordr.Transaction.PaymentMethod, &ordr.CustomerName, &ordr.CustomerPhone, &ordr.Pax) - if err != nil { - logger.ContextLogger(ctx).Error("error scanning rows", zap.Error(err)) - return nil, err - } - - ordr.OrderItem = append(ordr.OrderItem, oi) - } - - orders = &ordr - - if orders == nil { - return nil, fmt.Errorf("order not found") - } - - return orders, nil + return &order, nil } -func (b *OrderRepository) GetTotalRevenue(ctx context.Context, req entity.OrderTotalRevenueSearch) (float64, int64, error) { - var ( - totalmonthlyRevenue float64 - totalmonthlyTrans int64 - ) - - query := b.db.Table("orders"). - Select("COALESCE(sum(amount),0) as total_amount, COALESCE(count(id),0) as total_transaction"). - Where("status in ('NEW','PAID') ") - - if req.BranchID > 0 { - query = query.Where("branch_id = ?", req.BranchID) - } - - if req.Month > 0 { - query = query.Where("EXTRACT(MONTH FROM created_at) = ? ", req.Month) - } - - if req.Year > 0 { - query = query.Where("EXTRACT(YEAR FROM created_at) = ? ", req.Year) - } - - if req.DateStart != nil { - query = query.Where("created_at >= ? ", req.DateStart) - } - - if req.DateEnd != nil { - query = query.Where("created_at <= ? ", req.DateEnd) - } - - rows, err := query.Rows() - if err != nil { - return totalmonthlyRevenue, totalmonthlyTrans, err - } - defer rows.Close() - - for rows.Next() { - err := rows.Scan(&totalmonthlyRevenue, &totalmonthlyTrans) - if err != nil { - logger.ContextLogger(ctx).Error("error scanning rows", zap.Error(err)) - return totalmonthlyRevenue, totalmonthlyTrans, err - } - } - - return totalmonthlyRevenue, totalmonthlyTrans, nil -} - -func (b *OrderRepository) GetYearlyRevenue(ctx context.Context, year int) (entity.OrderYearlyRevenueList, error) { - var result entity.OrderYearlyRevenueList - - err := b.db.Raw(` SELECT - oi.item_type, - EXTRACT(MONTH FROM o.created_at) AS month_number, - SUM(oi.price ) AS total_amount - FROM - orders o - JOIN - order_items oi ON o.id = oi.order_id - WHERE - EXTRACT(YEAR FROM o.created_at) = ? - AND o.status IN ('NEW', 'PAID') - GROUP BY - EXTRACT(MONTH FROM o.created_at), - oi.item_type - ORDER BY - month_number, - oi.item_type`, year).Scan(&result).Error - - return result, err -} - -func (b *OrderRepository) GetBranchRevenue(ctx context.Context, req entity.OrderBranchRevenueSearch) (entity.OrderBranchRevenueList, error) { - var result entity.OrderBranchRevenueList - - query := b.db.Table("orders o"). - Joins("JOIN branches ON branches.id = o.branch_id"). - Select("o.branch_id, branches.name, branches.location, SUM(o.amount) as total_amount, COUNT(o.id) as total_trans"). - Where("o.status IN ('NEW', 'PAID')"). - Group("o.branch_id, branches.name, branches.location"). - Order("total_amount DESC, total_trans DESC") - - if req.DateStart != nil { - query = query.Where("o.created_at >= ? ", req.DateStart) - } - - if req.DateEnd != nil { - query = query.Where("o.created_at <= ? ", req.DateEnd) - } - - if err := query.Find(&result).Error; err != nil { - logger.ContextLogger(ctx).Error("error when GetBranchRevenue", zap.Error(err)) +func (r *OrderRepository) Update(ctx context.Context, order *entity.Order) (*entity.Order, error) { + if err := r.db.WithContext(ctx).Save(order).Error; err != nil { + logger.ContextLogger(ctx).Error("error when updating order", zap.Error(err)) return nil, err } - - return result, nil -} - -func logError(ctx context.Context, s string, err error) { - panic("unimplemented") + return order, nil } diff --git a/internal/repository/payment/payment.go b/internal/repository/payment/payment.go new file mode 100644 index 0000000..5291799 --- /dev/null +++ b/internal/repository/payment/payment.go @@ -0,0 +1,72 @@ +package payment + +import ( + "context" + "furtuna-be/internal/common/logger" + "furtuna-be/internal/entity" + "github.com/google/uuid" + "go.uber.org/zap" + "gorm.io/gorm" + "strconv" +) + +type PaymentRepository struct { + db *gorm.DB +} + +func NewPaymentRepository(db *gorm.DB) *PaymentRepository { + return &PaymentRepository{ + db: db, + } +} + +func (r *PaymentRepository) Create(ctx context.Context, payment *entity.Payment) (*entity.Payment, error) { + payment.ID = uuid.New() + if err := r.db.WithContext(ctx).Create(payment).Error; err != nil { + logger.ContextLogger(ctx).Error("error when creating payment", zap.Error(err)) + return nil, err + } + return payment, nil +} + +// Update updates an existing payment record in the database +func (r *PaymentRepository) Update(ctx context.Context, payment *entity.Payment) (*entity.Payment, error) { + if err := r.db.WithContext(ctx).Save(payment).Error; err != nil { + logger.ContextLogger(ctx).Error("error when updating payment", zap.Error(err)) + return nil, err + } + return payment, nil +} + +// FindByID retrieves a payment record by its ID +func (r *PaymentRepository) FindByID(ctx context.Context, id uuid.UUID) (*entity.Payment, error) { + payment := new(entity.Payment) + if err := r.db.WithContext(ctx).First(payment, id).Error; err != nil { + logger.ContextLogger(ctx).Error("error when finding payment by ID", zap.Error(err)) + return nil, err + } + return payment, nil +} + +func (r *PaymentRepository) FindByOrderAndPartnerID(ctx context.Context, orderID, partnerID int64) (*entity.Payment, error) { + payment := new(entity.Payment) + orderIDStr := strconv.FormatInt(orderID, 10) + partnerIDStr := strconv.FormatInt(partnerID, 10) + if err := r.db.WithContext(ctx). + Where("order_id = ? AND partner_id = ?", orderIDStr, partnerIDStr). + First(payment).Error; err != nil { + logger.ContextLogger(ctx).Error("error when finding payment by order ID and partner ID", zap.Error(err)) + return nil, err + } + return payment, nil +} + +// FindByReferenceID retrieves a payment record by its reference ID +func (r *PaymentRepository) FindByReferenceID(ctx context.Context, referenceID string) (*entity.Payment, error) { + payment := new(entity.Payment) + if err := r.db.WithContext(ctx).Where("reference_id = ?", referenceID).First(payment).Error; err != nil { + logger.ContextLogger(ctx).Error("error when finding payment by reference ID", zap.Error(err)) + return nil, err + } + return payment, nil +} diff --git a/internal/repository/products/product.go b/internal/repository/products/product.go index ba3d0c7..3f91df5 100644 --- a/internal/repository/products/product.go +++ b/internal/repository/products/product.go @@ -105,3 +105,12 @@ func (b *ProductRepository) DeleteProduct(ctx context.Context, id int64) error { } return nil } + +func (b *ProductRepository) GetProductsByIDs(ctx context.Context, ids []int64, partnerID int64) ([]*entity.ProductDB, error) { + var products []*entity.ProductDB + if err := b.db.Where("partner_id = ? AND id IN ?", partnerID, ids).Find(&products).Error; err != nil { + logger.ContextLogger(ctx).Error("error when getting products by IDs and partner ID", zap.Error(err)) + return nil, err + } + return products, nil +} diff --git a/internal/repository/repository.go b/internal/repository/repository.go index acf6018..47e0c2b 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -4,9 +4,11 @@ import ( "context" "database/sql" "furtuna-be/internal/repository/branches" + mdtrns "furtuna-be/internal/repository/midtrans" "furtuna-be/internal/repository/orders" "furtuna-be/internal/repository/oss" "furtuna-be/internal/repository/partners" + "furtuna-be/internal/repository/payment" "furtuna-be/internal/repository/products" "furtuna-be/internal/repository/sites" "furtuna-be/internal/repository/studios" @@ -24,36 +26,40 @@ import ( ) type RepoManagerImpl struct { - Crypto Crypto - Auth Auth - Event Event - User User - Branch Branch - Studio Studio - Product Product - Order Order - OSS OSSRepository - Partner PartnerRepository - Site SiteRepository - Trx TransactionManager - Wallet WalletRepository + Crypto Crypto + Auth Auth + Event Event + User User + Branch Branch + Studio Studio + Product Product + Order Order + OSS OSSRepository + Partner PartnerRepository + Site SiteRepository + Trx TransactionManager + Wallet WalletRepository + Midtrans Midtrans + Payment Payment } func NewRepoManagerImpl(db *gorm.DB, cfg *config.Config) *RepoManagerImpl { return &RepoManagerImpl{ - Crypto: crypto.NewCrypto(cfg.Auth()), - Auth: auth.NewAuthRepository(db), - Event: event.NewEventRepo(db), - User: users.NewUserRepository(db), - Branch: branches.NewBranchRepository(db), - Studio: studios.NewStudioRepository(db), - Product: products.NewProductRepository(db), - Order: orders.NewOrderRepository(db), - OSS: oss.NewOssRepositoryImpl(cfg.OSSConfig), - Partner: partners.NewPartnerRepository(db), - Site: sites.NewSiteRepository(db), - Trx: trx.NewGormTransactionManager(db), - Wallet: repository.NewWalletRepository(db), + Crypto: crypto.NewCrypto(cfg.Auth()), + Auth: auth.NewAuthRepository(db), + Event: event.NewEventRepo(db), + User: users.NewUserRepository(db), + Branch: branches.NewBranchRepository(db), + Studio: studios.NewStudioRepository(db), + Product: products.NewProductRepository(db), + Order: orders.NewOrderRepository(db), + OSS: oss.NewOssRepositoryImpl(cfg.OSSConfig), + Partner: partners.NewPartnerRepository(db), + Site: sites.NewSiteRepository(db), + Trx: trx.NewGormTransactionManager(db), + Wallet: repository.NewWalletRepository(db), + Midtrans: mdtrns.New(&cfg.Midtrans), + Payment: payment.NewPaymentRepository(db), } } @@ -73,6 +79,8 @@ type Crypto interface { CompareHashAndPassword(hash string, password string) bool ValidateWT(tokenString string) (*jwt.Token, error) GenerateJWT(user *entity.User) (string, error) + GenerateJWTOrder(order *entity.Order) (string, error) + ValidateJWTOrder(tokenString string) (int64, int64, error) ParseAndValidateJWT(token string) (*entity.JWTAuthClaims, error) } @@ -106,16 +114,13 @@ type Product interface { GetProductByID(ctx context.Context, id int64) (*entity.ProductDB, error) GetAllProducts(ctx context.Context, req entity.ProductSearch) (entity.ProductList, int, error) DeleteProduct(ctx context.Context, id int64) error + GetProductsByIDs(ctx context.Context, ids []int64, partnerID int64) ([]*entity.ProductDB, error) } type Order interface { - CreateOrder(ctx context.Context, order *entity.OrderDB) (*entity.OrderDB, error) - UpdateOrder(ctx context.Context, order *entity.OrderDB) (*entity.OrderDB, error) - GetOrderByID(ctx context.Context, id int64) (*entity.OrderDB, error) - GetAllOrders(ctx context.Context, req entity.OrderSearch) (entity.OrderList, int, error) - GetTotalRevenue(ctx context.Context, req entity.OrderTotalRevenueSearch) (float64, int64, error) - GetYearlyRevenue(ctx context.Context, year int) (entity.OrderYearlyRevenueList, error) - GetBranchRevenue(ctx context.Context, req entity.OrderBranchRevenueSearch) (entity.OrderBranchRevenueList, error) + Create(ctx context.Context, order *entity.Order) (*entity.Order, error) + FindByID(ctx context.Context, id int64) (*entity.Order, error) + Update(ctx context.Context, order *entity.Order) (*entity.Order, error) } type OSSRepository interface { @@ -150,3 +155,13 @@ type TransactionManager interface { type WalletRepository interface { Create(ctx context.Context, tx *gorm.DB, wallet *entity.Wallet) (*entity.Wallet, error) } + +type Midtrans interface { + CreatePayment(order entity.MidtransRequest) (*entity.MidtransResponse, error) +} + +type Payment interface { + Create(ctx context.Context, payment *entity.Payment) (*entity.Payment, error) + Update(ctx context.Context, payment *entity.Payment) (*entity.Payment, error) + FindByOrderAndPartnerID(ctx context.Context, orderID, partnerID int64) (*entity.Payment, error) +} diff --git a/internal/services/order/order.go b/internal/services/order/order.go index 2113a19..62c02a1 100644 --- a/internal/services/order/order.go +++ b/internal/services/order/order.go @@ -1,147 +1,221 @@ package order import ( - "context" - "fmt" + "encoding/json" + "errors" "furtuna-be/internal/common/logger" - "furtuna-be/internal/common/mycontext" - "furtuna-be/internal/constants/order" - "furtuna-be/internal/constants/transaction" + order2 "furtuna-be/internal/constants/order" "furtuna-be/internal/entity" "furtuna-be/internal/repository" - + "furtuna-be/internal/utils/generator" "go.uber.org/zap" + "golang.org/x/net/context" + "gorm.io/gorm" + "strconv" + "time" ) type OrderService struct { - repo repository.Order - prodRepo repository.Product - studioRepo repository.Studio + repo repository.Order + crypt repository.Crypto + product repository.Product + midtrans repository.Midtrans + payment repository.Payment } -func NewOrderService(repo repository.Order, prodRepo repository.Product, studioRepo repository.Studio) *OrderService { +func NewOrderService(repo repository.Order, product repository.Product, crypt repository.Crypto, + midtrans repository.Midtrans, payment repository.Payment) *OrderService { return &OrderService{ - repo: repo, - prodRepo: prodRepo, - studioRepo: studioRepo, + repo: repo, + product: product, + crypt: crypt, + midtrans: midtrans, + payment: payment, } } -func (o *OrderService) Create(ctx mycontext.Context, req *entity.Order) error { +func (s *OrderService) CreateOrder(ctx context.Context, req *entity.OrderRequest) (*entity.OrderResponse, error) { + productIDs := make([]int64, len(req.OrderItems)) + for i, item := range req.OrderItems { + productIDs[i] = item.ProductID + } - for i, oi := range req.OrderItem { - if oi.ItemType.IsProduct() { - item, err := o.prodRepo.GetProductByID(ctx, oi.ItemID) - if err != nil { - logger.ContextLogger(ctx).Error("error when get product item", zap.Error(err)) - return err - } + products, err := s.product.GetProductsByIDs(ctx, productIDs, req.PartnerID) + if err != nil { + logger.ContextLogger(ctx).Error("error when getting products by IDs", zap.Error(err)) + return nil, err + } - req.OrderItem[i].Price = item.Price - req.OrderItem[i].CreatedBy = ctx.RequestedBy() - } else if oi.ItemType.IsStudio() { - //get data studio - item, err := o.studioRepo.GetStudioByID(ctx, oi.ItemID) - if err != nil { - logger.ContextLogger(ctx).Error("error when get studio item", zap.Error(err)) - return err - } + productMap := make(map[int64]*entity.ProductDB) + for _, product := range products { + productMap[product.ID] = product + } - req.OrderItem[i].Price = item.Price - req.OrderItem[i].CreatedBy = ctx.RequestedBy() + totalAmount := 0.0 + for _, item := range req.OrderItems { + product, ok := productMap[item.ProductID] + if !ok { + logger.ContextLogger(ctx).Error("product not found", zap.Int64("productID", item.ProductID)) + return nil, errors.New("product not found") } - + totalAmount += product.Price * float64(item.Quantity) } - orderDB := req.ToOrderDB() - orderDB.CreatedBy = ctx.RequestedBy() - orderDB.Transaction.CreatedBy = ctx.RequestedBy() - - //set status - orderDB.Status = order.Paid - orderDB.Transaction.Status = transaction.Paid - - orderDB, err := o.repo.CreateOrder(ctx, orderDB) - if err != nil { - logger.ContextLogger(ctx).Error("error when create order", zap.Error(err)) - return err + order := &entity.Order{ + PartnerID: req.PartnerID, + RefID: generator.GenerateUUID(), + Status: order2.New.String(), + Amount: totalAmount, + PaymentType: req.PaymentMethod, + CreatedBy: req.CreatedBy, + OrderItems: []entity.OrderItem{}, } - return nil -} + for _, item := range req.OrderItems { + order.OrderItems = append(order.OrderItems, entity.OrderItem{ + ItemID: item.ProductID, + ItemType: productMap[item.ProductID].Type, + Price: productMap[item.ProductID].Price, + Quantity: item.Quantity, + CreatedBy: req.CreatedBy, + }) + } -func (s *OrderService) GetByID(ctx context.Context, id int64) (*entity.Order, error) { - orderDB, err := s.repo.GetOrderByID(ctx, id) + order, err = s.repo.Create(ctx, order) if err != nil { - logger.ContextLogger(ctx).Error("error when get order by id", zap.Error(err)) + logger.ContextLogger(ctx).Error("error when creating order", zap.Error(err)) return nil, err } - return orderDB.ToOrder(), nil -} - -func (s *OrderService) GetAll(ctx context.Context, search entity.OrderSearch) ([]*entity.Order, int, error) { - orders, total, err := s.repo.GetAllOrders(ctx, search) + token, err := s.crypt.GenerateJWTOrder(order) if err != nil { - logger.ContextLogger(ctx).Error("error when get all orders", zap.Error(err)) - return nil, 0, err - } - - return orders.ToOrderList(), total, nil -} - -func (s *OrderService) GetTotalRevenue(ctx context.Context, search entity.OrderTotalRevenueSearch) (float64, int64, error) { - rev, trans, err := s.repo.GetTotalRevenue(ctx, search) - if err != nil { - logger.ContextLogger(ctx).Error("error when get total revenue orders", zap.Error(err)) - return 0, 0, err - } - - return rev, trans, nil -} - -func (s *OrderService) GetYearlyRevenue(ctx context.Context, year int) (entity.OrderYearlyRevenueList, error) { - result, err := s.repo.GetYearlyRevenue(ctx, year) - if err != nil { - logger.ContextLogger(ctx).Error("error when get yearly revenue orders", zap.Error(err)) + logger.ContextLogger(ctx).Error("error when create token", zap.Error(err)) return nil, err } - return result, nil + return &entity.OrderResponse{ + Order: order, + Token: token, + }, nil } -func (s *OrderService) GetBranchRevenue(ctx context.Context, req entity.OrderBranchRevenueSearch) (entity.OrderBranchRevenueList, error) { - result, err := s.repo.GetBranchRevenue(ctx, req) +func (s *OrderService) Execute(ctx context.Context, req *entity.OrderExecuteRequest) (*entity.ExecuteOrderResponse, error) { + partnerID, orderID, err := s.crypt.ValidateJWTOrder(req.Token) if err != nil { - logger.ContextLogger(ctx).Error("error when get branch revenue orders", zap.Error(err)) + logger.ContextLogger(ctx).Error("error when validating JWT order", zap.Error(err)) return nil, err } - return result, nil -} - -func (s *OrderService) UpdateStatus(ctx mycontext.Context, id int64, orderReq *entity.Order) (*entity.Order, error) { - existingOrder, err := s.repo.GetOrderByID(ctx, id) + order, err := s.repo.FindByID(ctx, orderID) if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + logger.ContextLogger(ctx).Error("order not found", zap.Int64("orderID", orderID)) + return nil, errors.New("order not found") + } + logger.ContextLogger(ctx).Error("error when finding order by ID", zap.Error(err)) return nil, err } - //validate state - if !existingOrder.Status.IsNew() { - return nil, fmt.Errorf("Invalid order status") - } - - if existingOrder.Status == orderReq.Status { - return nil, fmt.Errorf("Order status already %s", existingOrder.Status) - } - - existingOrder.ToUpdatedOrder(ctx.RequestedBy(), *orderReq) - - _, err = s.repo.UpdateOrder(ctx, existingOrder) - if err != nil { - logger.ContextLogger(ctx).Error("error when update user", zap.Error(err)) + // Check for existing payment to handle idempotency + payment, err := s.payment.FindByOrderAndPartnerID(ctx, orderID, partnerID) + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.ContextLogger(ctx).Error("error getting payment data from db", zap.Error(err)) return nil, err } - return existingOrder.ToOrder(), nil + if payment != nil { + return s.createExecuteOrderResponse(order, payment), nil + } + + if order.PartnerID != partnerID { + logger.ContextLogger(ctx).Error("partner ID mismatch", zap.Int64("orderID", orderID), zap.Int64("tokenPartnerID", partnerID), zap.Int64("orderPartnerID", order.PartnerID)) + return nil, errors.New("partner ID mismatch") + } + + if order.Status != "NEW" { + return nil, errors.New("invalid state") + } + + resp := &entity.ExecuteOrderResponse{ + Order: order, + } + + if order.PaymentType != "CASH" { + paymentResponse, err := s.processNonCashPayment(ctx, order, partnerID, req.CreatedBy) + if err != nil { + return nil, err + } + resp.PaymentToken = paymentResponse.Token + resp.RedirectURL = paymentResponse.RedirectURL + } + + order.SetExecutePaymentStatus() + order, err = s.repo.Update(ctx, order) + if err != nil { + logger.ContextLogger(ctx).Error("error when updating order status", zap.Error(err)) + return nil, err + } + + return resp, nil +} + +func (s *OrderService) createExecuteOrderResponse(order *entity.Order, payment *entity.Payment) *entity.ExecuteOrderResponse { + var metadata map[string]string + if err := json.Unmarshal(payment.RequestMetadata, &metadata); err != nil { + logger.ContextLogger(context.Background()).Error("error unmarshaling request metadata", zap.Error(err)) + return &entity.ExecuteOrderResponse{ + Order: order, + } + } + return &entity.ExecuteOrderResponse{ + Order: order, + PaymentToken: metadata["payment_token"], + RedirectURL: metadata["payment_redirect_url"], + } +} + +func (s *OrderService) processNonCashPayment(ctx context.Context, order *entity.Order, partnerID, createdBy int64) (*entity.MidtransResponse, error) { + paymentRequest := entity.MidtransRequest{ + PaymentReferenceID: generator.GenerateUUIDV4(), + TotalAmount: int64(order.Amount), + OrderItems: order.OrderItems, + } + + paymentResponse, err := s.midtrans.CreatePayment(paymentRequest) + if err != nil { + logger.ContextLogger(ctx).Error("error when creating payment", zap.Error(err)) + return nil, err + } + + requestMetadata, err := json.Marshal(map[string]string{ + "partner_id": strconv.FormatInt(partnerID, 10), + "created_by": strconv.FormatInt(createdBy, 10), + "payment_token": paymentResponse.Token, + "payment_redirect_url": paymentResponse.RedirectURL, + }) + if err != nil { + logger.ContextLogger(ctx).Error("error when marshaling request metadata", zap.Error(err)) + return nil, err + } + + payment := &entity.Payment{ + PartnerID: strconv.FormatInt(partnerID, 10), + OrderID: strconv.FormatInt(order.ID, 10), + ReferenceID: paymentRequest.PaymentReferenceID, + Channel: "xendit", + PaymentType: order.PaymentType, + Amount: order.Amount, + State: "pending", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + RequestMetadata: requestMetadata, + } + + _, err = s.payment.Create(ctx, payment) + if err != nil { + logger.ContextLogger(ctx).Error("error when creating payment record", zap.Error(err)) + return nil, err + } + + return paymentResponse, nil } diff --git a/internal/services/service.go b/internal/services/service.go index 99b122b..0610fd0 100644 --- a/internal/services/service.go +++ b/internal/services/service.go @@ -41,7 +41,7 @@ func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) BranchSvc: branch.NewBranchService(repo.Branch), StudioSvc: studio.NewStudioService(repo.Studio), ProductSvc: product.NewProductService(repo.Product), - OrderSvc: order.NewOrderService(repo.Order, repo.Product, repo.Studio), + OrderSvc: order.NewOrderService(repo.Order, repo.Product, repo.Crypto, repo.Midtrans, repo.Payment), OSSSvc: oss.NewOSSService(repo.OSS), PartnerSvc: partner.NewPartnerService( repo.Partner, users.NewUserService(repo.User, repo.Branch), repo.Trx, repo.Wallet), @@ -94,13 +94,8 @@ type Product interface { } type Order interface { - Create(ctx mycontext.Context, req *entity.Order) error - UpdateStatus(ctx mycontext.Context, id int64, orderReq *entity.Order) (*entity.Order, error) - GetByID(ctx context.Context, id int64) (*entity.Order, error) - GetAll(ctx context.Context, search entity.OrderSearch) ([]*entity.Order, int, error) - GetTotalRevenue(ctx context.Context, search entity.OrderTotalRevenueSearch) (float64, int64, error) - GetYearlyRevenue(ctx context.Context, year int) (entity.OrderYearlyRevenueList, error) - GetBranchRevenue(ctx context.Context, req entity.OrderBranchRevenueSearch) (entity.OrderBranchRevenueList, error) + CreateOrder(ctx context.Context, req *entity.OrderRequest) (*entity.OrderResponse, error) + Execute(ctx context.Context, req *entity.OrderExecuteRequest) (*entity.ExecuteOrderResponse, error) } type OSSService interface { diff --git a/internal/utils/generator/string-generator.go b/internal/utils/generator/string-generator.go index b295bc0..ae26339 100644 --- a/internal/utils/generator/string-generator.go +++ b/internal/utils/generator/string-generator.go @@ -2,6 +2,7 @@ package generator import ( "fmt" + uuid2 "github.com/gofrs/uuid" "math/rand" "strconv" "time" @@ -34,3 +35,8 @@ func GenerateUUID() string { id := uuid.New() return id.String() } + +func GenerateUUIDV4() string { + id, _ := uuid2.NewV4() + return id.String() +} diff --git a/migrations/000001_add_table_user.up.sql b/migrations/000001_add_table_user.up.sql index 3571640..02c8e0f 100644 --- a/migrations/000001_add_table_user.up.sql +++ b/migrations/000001_add_table_user.up.sql @@ -1,3 +1,5 @@ +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + CREATE TABLE users ( id BIGSERIAL, diff --git a/migrations/000004_partner-table.down.sql b/migrations/000004_partner-table.down.sql index 6bf90a9..213bdc1 100644 --- a/migrations/000004_partner-table.down.sql +++ b/migrations/000004_partner-table.down.sql @@ -1 +1 @@ -DROP TABLE partners; +DROP TABLE partners CASCADE; diff --git a/migrations/000007_add-table-order.down.sql b/migrations/000007_add-table-order.down.sql index 247916e..4b96709 100644 --- a/migrations/000007_add-table-order.down.sql +++ b/migrations/000007_add-table-order.down.sql @@ -1 +1 @@ -DROP TABLE orders; \ No newline at end of file +DROP TABLE orders cascade; \ No newline at end of file diff --git a/migrations/000007_add-table-order.up.sql b/migrations/000007_add-table-order.up.sql index 8a9d2a9..79ac58d 100644 --- a/migrations/000007_add-table-order.up.sql +++ b/migrations/000007_add-table-order.up.sql @@ -1,9 +1,8 @@ CREATE TABLE orders ( id BIGSERIAL PRIMARY KEY, - ref_id UUID, - external_id varchar, - branch_id INTEGER, + ref_id varchar, + partner_id INTEGER, status VARCHAR, amount DECIMAL NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT NOW(), diff --git a/migrations/000009_add_wallet.down.sql b/migrations/000009_add_wallet.down.sql index e69de29..a2b5ffd 100644 --- a/migrations/000009_add_wallet.down.sql +++ b/migrations/000009_add_wallet.down.sql @@ -0,0 +1 @@ +DROP TABLE wallets cascade; \ No newline at end of file diff --git a/migrations/000010_add-payment-table.down.sql b/migrations/000010_add-payment-table.down.sql new file mode 100644 index 0000000..caf1014 --- /dev/null +++ b/migrations/000010_add-payment-table.down.sql @@ -0,0 +1 @@ +DROP TABLE payments cascade; \ No newline at end of file diff --git a/migrations/000010_add-payment-table.up.sql b/migrations/000010_add-payment-table.up.sql new file mode 100644 index 0000000..2b242a0 --- /dev/null +++ b/migrations/000010_add-payment-table.up.sql @@ -0,0 +1,16 @@ +CREATE TABLE public.payments +( + id uuid NOT NULL DEFAULT uuid_generate_v4(), + partner_id varchar NOT NULL, + order_id varchar NOT NULL, + reference_id varchar NOT NULL, + channel varchar NOT NULL, + payment_type varchar NOT NULL, + amount numeric NOT NULL, + state varchar NOT NULL, + request_metadata json NOT NULL, + created_at timestamp NOT NULL, + updated_at timestamp NOT NULL, + finished_at timestamp NOT NULL, + CONSTRAINT payment_pkey PRIMARY KEY (id) +); \ No newline at end of file