diff --git a/payment/WSS Payment.postman_collection.json b/payment/WSS Payment.postman_collection.json index ccc526eb..6617c2e2 100644 --- a/payment/WSS Payment.postman_collection.json +++ b/payment/WSS Payment.postman_collection.json @@ -167,50 +167,6 @@ "cookie": [], "body": "\"empty buying_goods\"" }, - { - "name": "N/A Good", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"user_id\": 1234,\n \"to_pay_amount\": 1000,\n \"discount_amount\": 1000,\n \"description\": \"Sample description\",\n \"buying_goods\": [\"not-available-good\"],\n \"name\": \"Crow\",\n \"phone\": \"09123456789\",\n \"mail\": \"crow.nest@gmail.com\",\n \"callback_url\": \"https://google.com/\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{BASE_URL}}/create", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "create" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Date", - "value": "Thu, 28 Dec 2023 20:47:33 GMT" - }, - { - "key": "Content-Length", - "value": "38" - } - ], - "cookie": [], - "body": "\"cannot find good: not-available-good\"" - }, { "name": "IDPay Failed", "originalRequest": { @@ -453,268 +409,6 @@ } ] }, - { - "name": "Goods", - "item": [ - { - "name": "List Goods", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{BASE_URL}}/goods", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "goods" - ] - } - }, - "response": [ - { - "name": "New Request", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{BASE_URL}}/goods", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "goods" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Date", - "value": "Thu, 28 Dec 2023 19:56:56 GMT" - }, - { - "key": "Content-Length", - "value": "123" - } - ], - "cookie": [], - "body": "[\n {\n \"ID\": 1,\n \"Name\": \"kir\",\n \"Price\": 420,\n \"Description\": \"random description\"\n },\n {\n \"ID\": 5,\n \"Name\": \"kir2\",\n \"Price\": 1000,\n \"Description\": \"\"\n }\n]" - } - ] - }, - { - "name": "Add Good", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"kir\",\n \"price\": 420,\n \"description\": \"random description\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{BASE_URL}}/goods", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "goods" - ] - }, - "description": "Adds a \"good\" to database. A \"good\" is basically an item which can be bought once for each user. This endpoint can create one of them in order to allow the admins to add items on fly.\n\nThe body of this endpoint consists of 3 key and values:\n\n- `name`: The name of the good. This must be unique.\n- `price`: The price of the good. Must be more than zero.\n- `description`(Optional): An description which is only stored in database.\n \n\nThis endpoint returns the ID of the newly created object." - }, - "response": [ - { - "name": "Add Good", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"kir\",\n \"price\": 420,\n \"description\": \"this is a description\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{BASE_URL}}/goods", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "goods" - ] - } - }, - "status": "Created", - "code": 201, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Date", - "value": "Thu, 28 Dec 2023 19:42:26 GMT" - }, - { - "key": "Content-Length", - "value": "8" - } - ], - "cookie": [], - "body": "{\n \"id\": 1\n}" - }, - { - "name": "Add Good Without Description", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"kir2\",\n \"price\": 1000\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{BASE_URL}}/goods", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "goods" - ] - } - }, - "status": "Created", - "code": 201, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Date", - "value": "Thu, 28 Dec 2023 19:42:56 GMT" - }, - { - "key": "Content-Length", - "value": "8" - } - ], - "cookie": [], - "body": "{\n \"id\": 2\n}" - }, - { - "name": "Existing Good", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"kir\",\n \"price\": 420,\n \"description\": \"random description\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{BASE_URL}}/goods", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "goods" - ] - } - }, - "status": "Conflict", - "code": 409, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Date", - "value": "Thu, 28 Dec 2023 19:55:39 GMT" - }, - { - "key": "Content-Length", - "value": "21" - } - ], - "cookie": [], - "body": "\"good already exists\"" - }, - { - "name": "Invalid Price", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"kir\",\n \"price\": 0,\n \"description\": \"random description\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{BASE_URL}}/goods", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "goods" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "plain", - "header": [ - { - "key": "Date", - "value": "Thu, 28 Dec 2023 20:32:00 GMT" - }, - { - "key": "Content-Length", - "value": "96" - }, - { - "key": "Content-Type", - "value": "text/plain; charset=utf-8" - } - ], - "cookie": [], - "body": "\"Key: 'createGoodRequest.Price' Error:Field validation for 'Price' failed on the 'required' tag\"" - } - ] - } - ] - }, { "name": "Health Check", "request": { diff --git a/payment/api/goods.go b/payment/api/goods.go deleted file mode 100644 index 9b8acb98..00000000 --- a/payment/api/goods.go +++ /dev/null @@ -1,53 +0,0 @@ -package api - -import ( - "errors" - "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - "gorm.io/gorm" - "net/http" - "wss-payment/internal/database" -) - -// GetGoods gets all goods registered in database -func (api *API) GetGoods(c *gin.Context) { - goods, err := api.Database.GetGoods() - if err != nil { - log.WithError(err).Error("cannot get goods") - c.JSON(http.StatusInternalServerError, "cannot get goods: "+err.Error()) - return - } - c.JSON(http.StatusOK, goods) -} - -// AddGood adds a good to server -func (api *API) AddGood(c *gin.Context) { - // Parse body - var body createGoodRequest - err := c.BindJSON(&body) - if err != nil { - c.JSON(http.StatusBadRequest, "cannot parse body: "+err.Error()) - return - } - logger := log.WithField("body", body) - // Create it in database - good := database.Good{ - Name: body.Name, - Price: body.Price, - Description: body.Description, - } - err = api.Database.AddGood(&good) - if err != nil { - if errors.Is(err, gorm.ErrDuplicatedKey) { - logger.Warn("good already exists") - c.JSON(http.StatusConflict, "good already exists") - } else { - logger.WithError(err).Error("cannot insert body in database") - c.JSON(http.StatusInternalServerError, "cannot insert body in database: "+err.Error()) - } - return - } - logger.Info("added good to database") - // Report back to endpoint - c.JSON(http.StatusCreated, createGoodResponse{good.ID}) -} diff --git a/payment/api/idpay.go b/payment/api/idpay.go index 42b9e9d6..e0cd3929 100644 --- a/payment/api/idpay.go +++ b/payment/api/idpay.go @@ -27,21 +27,11 @@ func (api *API) CreateTransaction(c *gin.Context) { c.JSON(http.StatusBadRequest, "empty buying_goods") return } - // Try to get the list of goods from database. This will fail if user has bought something - // from its BuyingGoods before - goods, err := api.Database.GetGoodsFromName(body.BuyingGoods) - if err != nil { - var goodError database.GoodNotFoundError - if errors.As(err, &goodError) { - logger.WithError(err).Warn("unknown good") - c.JSON(http.StatusBadRequest, err.Error()) - } else { - logger.WithError(err).Error("cannot query goods") - c.JSON(http.StatusInternalServerError, "cannot query goods: "+err.Error()) - } - return - } // Now we try to insert it in database. This should probably succeed + goods := make([]database.Good, len(body.BuyingGoods)) + for i := range body.BuyingGoods { + goods[i] = database.Good{Name: body.BuyingGoods[i]} + } payment := database.Payment{ UserID: body.UserID, ToPayAmount: body.ToPayAmount, diff --git a/payment/cmd/payment/main.go b/payment/cmd/payment/main.go index 711c0481..01770d66 100644 --- a/payment/cmd/payment/main.go +++ b/payment/cmd/payment/main.go @@ -32,8 +32,6 @@ func main() { r.GET("/health", api.HealthCheck) r.POST("/transaction", endpointApi.CreateTransaction) r.GET("/transaction", endpointApi.GetTransaction) - r.GET("/goods", endpointApi.GetGoods) - r.POST("/goods", endpointApi.AddGood) // Listen srv := &http.Server{ Handler: r, diff --git a/payment/internal/database/payment.go b/payment/internal/database/payment.go index 23cdf807..fac12e31 100644 --- a/payment/internal/database/payment.go +++ b/payment/internal/database/payment.go @@ -2,41 +2,11 @@ package database import ( "database/sql" - "github.com/go-faster/errors" "github.com/google/uuid" log "github.com/sirupsen/logrus" - "gorm.io/gorm" "time" ) -// GetGoods gets the list of all goods in database -func (db PaymentDatabase) GetGoods() ([]Good, error) { - var payments []Good - result := db.db.Find(&payments) - return payments, result.Error -} - -// GetGoodsFromName gets the list of all goods from their name in database -func (db PaymentDatabase) GetGoodsFromName(names []string) ([]Good, error) { - // TODO: There SHOULD be a better way - result := make([]Good, len(names)) - for i, name := range names { - if err := db.db.Where("name = ?", name).First(&result[i]).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, GoodNotFoundError{GoodName: name} - } else { - return nil, errors.Wrap(err, "cannot query database") - } - } - } - return result, nil -} - -// AddGood adds a good to the table -func (db PaymentDatabase) AddGood(good *Good) error { - return db.db.Create(good).Error -} - // InitiateTransaction will add the given Payment in database with status set to initialized func (db PaymentDatabase) InitiateTransaction(payment *Payment) error { // At first initialize some values diff --git a/payment/internal/database/pg.go b/payment/internal/database/pg.go index 82018e66..a5a11e50 100644 --- a/payment/internal/database/pg.go +++ b/payment/internal/database/pg.go @@ -16,7 +16,7 @@ func NewPostgres(dsn string) (PaymentDatabase, error) { return PaymentDatabase{}, errors.Wrap(err, "cannot open database") } // Gorm automatically pings the database thus we can just migrate tables - err = db.AutoMigrate(Good{}, Payment{}) + err = db.AutoMigrate(Payment{}, Good{}) if err != nil { return PaymentDatabase{}, errors.Wrap(err, "cannot migrate database") } diff --git a/payment/internal/database/types.go b/payment/internal/database/types.go index aec02d5c..e15870ef 100644 --- a/payment/internal/database/types.go +++ b/payment/internal/database/types.go @@ -52,7 +52,7 @@ type Payment struct { // What is the status of this payment? PaymentStatus PaymentStatus `gorm:"not null"` // List of the Goos which this user has bought in this payment - BoughtGoods []Good `gorm:"many2many:bought_goods;"` + BoughtGoods []Good // When was this payment created? CreatedAt time.Time `gorm:"not null"` // When was it verified? (could be null) @@ -62,10 +62,8 @@ type Payment struct { type Good struct { // ID of this good ID uint32 `gorm:"primarykey"` + // To what payment does this belong? + PaymentOrderID uuid.UUID // Name of it - Name string `gorm:"unique;not null" ` - // The price of this item - Price uint64 `gorm:"not null"` - // An optional description about this payment - Description string `gorm:"not null"` + Name string `gorm:"not null"` }