add product image
This commit is contained in:
parent
9ebacf85aa
commit
c7422da71a
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
*.env
|
*.env
|
||||||
|
public
|
@ -3,33 +3,59 @@ package api
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
db "git.nochill.in/nochill/naice_pos/db/sqlc"
|
db "git.nochill.in/nochill/naice_pos/db/sqlc"
|
||||||
"git.nochill.in/nochill/naice_pos/token"
|
"git.nochill.in/nochill/naice_pos/token"
|
||||||
|
"git.nochill.in/nochill/naice_pos/util"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type createProductRequest struct {
|
type createProductRequest struct {
|
||||||
Name string `json:"name" binding:"required"`
|
Name string `form:"name" binding:"required"`
|
||||||
SellingPrice float64 `json:"selling_price" binding:"required"`
|
SellingPrice float64 `form:"selling_price" binding:"required"`
|
||||||
ProductTypeID int16 `json:"product_type_id" binding:"required"`
|
ProductTypeID int16 `form:"product_type_id" binding:"required"`
|
||||||
PurchasePrice float64 `json:"purchase_price" binding:"required"`
|
PurchasePrice float64 `form:"purchase_price" binding:"required"`
|
||||||
ProductCategoryID string `json:"product_category_id" binding:"required"`
|
ProductCategoryID string `form:"product_category_id" binding:"required"`
|
||||||
Stock float64 `json:"stock" binding:"number"`
|
Stock float64 `form:"stock" binding:"number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) createProduct(ctx *gin.Context) {
|
func (server *Server) createProduct(ctx *gin.Context) {
|
||||||
var req createProductRequest
|
var req createProductRequest
|
||||||
|
var imagePath string
|
||||||
|
|
||||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
file, _ := ctx.FormFile("image")
|
||||||
|
|
||||||
|
if err := ctx.Bind(&req); err != nil {
|
||||||
ctx.JSON(http.StatusBadRequest, errorResponse(err, ""))
|
ctx.JSON(http.StatusBadRequest, errorResponse(err, ""))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload)
|
authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload)
|
||||||
|
|
||||||
|
if file != nil {
|
||||||
|
file := file
|
||||||
|
fileExt := filepath.Ext(file.Filename)
|
||||||
|
now := time.Now()
|
||||||
|
dir := fmt.Sprintf("public/upload/images/%s/products", authPayload.MerchantID)
|
||||||
|
filename := fmt.Sprintf("%s%s%s", util.RandomString(5), fmt.Sprintf("%v", now.Unix()), fileExt)
|
||||||
|
imagePath = fmt.Sprintf("%s/%s", dir, filename)
|
||||||
|
|
||||||
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||||
|
os.Mkdir(dir, 0775)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ctx.SaveUploadedFile(file, fmt.Sprintf("%s", imagePath)); err != nil {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err, ""))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
arg := db.CreateProductParams{
|
arg := db.CreateProductParams{
|
||||||
MerchantID: authPayload.MerchantID,
|
MerchantID: authPayload.MerchantID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
@ -38,6 +64,7 @@ func (server *Server) createProduct(ctx *gin.Context) {
|
|||||||
PurchasePrice: req.PurchasePrice,
|
PurchasePrice: req.PurchasePrice,
|
||||||
ProductCategoryID: uuid.MustParse(req.ProductCategoryID),
|
ProductCategoryID: uuid.MustParse(req.ProductCategoryID),
|
||||||
Stock: req.Stock,
|
Stock: req.Stock,
|
||||||
|
Image: sql.NullString{Valid: len(imagePath) > 0, String: imagePath},
|
||||||
}
|
}
|
||||||
|
|
||||||
product, err := server.store.CreateProduct(ctx, arg)
|
product, err := server.store.CreateProduct(ctx, arg)
|
||||||
@ -109,19 +136,38 @@ func (server *Server) listProducts(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type updateProductRequest struct {
|
type updateProductRequest struct {
|
||||||
ProductID uuid.UUID `json:"product_id" binding:"required"`
|
ProductID uuid.UUID `form:"product_id" binding:"required"`
|
||||||
Name string `json:"name" binding:"required"`
|
Name string `form:"name" binding:"required"`
|
||||||
SellingPrice float64 `json:"selling_price" binding:"required"`
|
SellingPrice float64 `form:"selling_price" binding:"required"`
|
||||||
PurchasePrice float64 `json:"purchase_price" binding:"required"`
|
PurchasePrice float64 `form:"purchase_price" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) updateProduct(ctx *gin.Context) {
|
func (server *Server) updateProduct(ctx *gin.Context) {
|
||||||
var req updateProductRequest
|
var req updateProductRequest
|
||||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
var imagePath string
|
||||||
|
file, _ := ctx.FormFile("image")
|
||||||
|
|
||||||
|
if err := ctx.Bind(&req); err != nil {
|
||||||
ctx.JSON(http.StatusBadRequest, errorResponse(err, ""))
|
ctx.JSON(http.StatusBadRequest, errorResponse(err, ""))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload)
|
||||||
|
|
||||||
|
if file != nil {
|
||||||
|
file := file
|
||||||
|
fileExt := filepath.Ext(file.Filename)
|
||||||
|
now := time.Now()
|
||||||
|
dir := fmt.Sprintf("public/upload/images/%s/products", authPayload.MerchantID)
|
||||||
|
filename := fmt.Sprintf("%s%s%s", util.RandomString(5), fmt.Sprintf("%v", now.Unix()), fileExt)
|
||||||
|
imagePath = fmt.Sprintf("%s/%s", dir, filename)
|
||||||
|
|
||||||
|
if err := ctx.SaveUploadedFile(file, fmt.Sprintf("%s", imagePath)); err != nil {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err, ""))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
arg := db.UpdateProductParams{
|
arg := db.UpdateProductParams{
|
||||||
ID: req.ProductID,
|
ID: req.ProductID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
|
@ -2,6 +2,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
db "git.nochill.in/nochill/naice_pos/db/sqlc"
|
db "git.nochill.in/nochill/naice_pos/db/sqlc"
|
||||||
"git.nochill.in/nochill/naice_pos/token"
|
"git.nochill.in/nochill/naice_pos/token"
|
||||||
@ -37,6 +38,7 @@ func (server *Server) getRoutes() {
|
|||||||
router.POST("/user/login", server.loginUser)
|
router.POST("/user/login", server.loginUser)
|
||||||
router.POST("/user/merchants", server.createUserMerchant)
|
router.POST("/user/merchants", server.createUserMerchant)
|
||||||
router.POST("/user/renew_token", server.renewAccessToken)
|
router.POST("/user/renew_token", server.renewAccessToken)
|
||||||
|
router.Static("/public", filepath.Base("public"))
|
||||||
|
|
||||||
apiRoutes := router.Group("/api").Use(authMiddleware(server.tokenMaker))
|
apiRoutes := router.Group("/api").Use(authMiddleware(server.tokenMaker))
|
||||||
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE product DROP COLUMN IF EXISTS image;
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE products ADD COLUMN image text;
|
@ -6,9 +6,10 @@ INSERT INTO products (
|
|||||||
product_type_id,
|
product_type_id,
|
||||||
purchase_price,
|
purchase_price,
|
||||||
product_category_id,
|
product_category_id,
|
||||||
|
image,
|
||||||
stock
|
stock
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, $3, $4, $5, $6, $7
|
$1, $2, $3, $4, $5, $6, $7, $8
|
||||||
)
|
)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
@ -36,7 +37,12 @@ OFFSET $3;
|
|||||||
|
|
||||||
-- name: UpdateProduct :one
|
-- name: UpdateProduct :one
|
||||||
UPDATE products
|
UPDATE products
|
||||||
SET name = $2, selling_price = $3, purchase_price = $4, product_category_id = $5, updated_at = $6
|
SET name = $2,
|
||||||
|
selling_price = $3,
|
||||||
|
purchase_price = $4,
|
||||||
|
product_category_id = $5,
|
||||||
|
image = $6,
|
||||||
|
updated_at = $7
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ type Product struct {
|
|||||||
CreatedAt sql.NullTime `json:"created_at"`
|
CreatedAt sql.NullTime `json:"created_at"`
|
||||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||||
ProductCategoryID uuid.UUID `json:"product_category_id"`
|
ProductCategoryID uuid.UUID `json:"product_category_id"`
|
||||||
|
Image sql.NullString `json:"image"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductCategory struct {
|
type ProductCategory struct {
|
||||||
|
@ -20,11 +20,12 @@ INSERT INTO products (
|
|||||||
product_type_id,
|
product_type_id,
|
||||||
purchase_price,
|
purchase_price,
|
||||||
product_category_id,
|
product_category_id,
|
||||||
|
image,
|
||||||
stock
|
stock
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, $3, $4, $5, $6, $7
|
$1, $2, $3, $4, $5, $6, $7, $8
|
||||||
)
|
)
|
||||||
RETURNING id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id
|
RETURNING id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id, image
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateProductParams struct {
|
type CreateProductParams struct {
|
||||||
@ -34,6 +35,7 @@ type CreateProductParams struct {
|
|||||||
ProductTypeID int16 `json:"product_type_id"`
|
ProductTypeID int16 `json:"product_type_id"`
|
||||||
PurchasePrice float64 `json:"purchase_price"`
|
PurchasePrice float64 `json:"purchase_price"`
|
||||||
ProductCategoryID uuid.UUID `json:"product_category_id"`
|
ProductCategoryID uuid.UUID `json:"product_category_id"`
|
||||||
|
Image sql.NullString `json:"image"`
|
||||||
Stock float64 `json:"stock"`
|
Stock float64 `json:"stock"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +47,7 @@ func (q *Queries) CreateProduct(ctx context.Context, arg CreateProductParams) (P
|
|||||||
arg.ProductTypeID,
|
arg.ProductTypeID,
|
||||||
arg.PurchasePrice,
|
arg.PurchasePrice,
|
||||||
arg.ProductCategoryID,
|
arg.ProductCategoryID,
|
||||||
|
arg.Image,
|
||||||
arg.Stock,
|
arg.Stock,
|
||||||
)
|
)
|
||||||
var i Product
|
var i Product
|
||||||
@ -60,6 +63,7 @@ func (q *Queries) CreateProduct(ctx context.Context, arg CreateProductParams) (P
|
|||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ProductCategoryID,
|
&i.ProductCategoryID,
|
||||||
|
&i.Image,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
@ -74,7 +78,7 @@ func (q *Queries) DeleteProduct(ctx context.Context, id uuid.UUID) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getProduct = `-- name: GetProduct :one
|
const getProduct = `-- name: GetProduct :one
|
||||||
SELECT id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id FROM products
|
SELECT id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id, image FROM products
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -93,12 +97,13 @@ func (q *Queries) GetProduct(ctx context.Context, id uuid.UUID) (Product, error)
|
|||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ProductCategoryID,
|
&i.ProductCategoryID,
|
||||||
|
&i.Image,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStockForUpdateStock = `-- name: GetStockForUpdateStock :one
|
const getStockForUpdateStock = `-- name: GetStockForUpdateStock :one
|
||||||
SELECT id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id FROM products
|
SELECT id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id, image FROM products
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
FOR NO KEY UPDATE
|
FOR NO KEY UPDATE
|
||||||
@ -119,12 +124,13 @@ func (q *Queries) GetStockForUpdateStock(ctx context.Context, id uuid.UUID) (Pro
|
|||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ProductCategoryID,
|
&i.ProductCategoryID,
|
||||||
|
&i.Image,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const listProducts = `-- name: ListProducts :many
|
const listProducts = `-- name: ListProducts :many
|
||||||
SELECT id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id FROM products
|
SELECT id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id, image FROM products
|
||||||
WHERE merchant_id = $1
|
WHERE merchant_id = $1
|
||||||
ORDER BY index_id
|
ORDER BY index_id
|
||||||
LIMIT $2
|
LIMIT $2
|
||||||
@ -158,6 +164,7 @@ func (q *Queries) ListProducts(ctx context.Context, arg ListProductsParams) ([]P
|
|||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ProductCategoryID,
|
&i.ProductCategoryID,
|
||||||
|
&i.Image,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -174,9 +181,14 @@ func (q *Queries) ListProducts(ctx context.Context, arg ListProductsParams) ([]P
|
|||||||
|
|
||||||
const updateProduct = `-- name: UpdateProduct :one
|
const updateProduct = `-- name: UpdateProduct :one
|
||||||
UPDATE products
|
UPDATE products
|
||||||
SET name = $2, selling_price = $3, purchase_price = $4, product_category_id = $5, updated_at = $6
|
SET name = $2,
|
||||||
|
selling_price = $3,
|
||||||
|
purchase_price = $4,
|
||||||
|
product_category_id = $5,
|
||||||
|
image = $6,
|
||||||
|
updated_at = $7
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id
|
RETURNING id, merchant_id, product_type_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id, image
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateProductParams struct {
|
type UpdateProductParams struct {
|
||||||
@ -185,6 +197,7 @@ type UpdateProductParams struct {
|
|||||||
SellingPrice float64 `json:"selling_price"`
|
SellingPrice float64 `json:"selling_price"`
|
||||||
PurchasePrice float64 `json:"purchase_price"`
|
PurchasePrice float64 `json:"purchase_price"`
|
||||||
ProductCategoryID uuid.UUID `json:"product_category_id"`
|
ProductCategoryID uuid.UUID `json:"product_category_id"`
|
||||||
|
Image sql.NullString `json:"image"`
|
||||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +208,7 @@ func (q *Queries) UpdateProduct(ctx context.Context, arg UpdateProductParams) (P
|
|||||||
arg.SellingPrice,
|
arg.SellingPrice,
|
||||||
arg.PurchasePrice,
|
arg.PurchasePrice,
|
||||||
arg.ProductCategoryID,
|
arg.ProductCategoryID,
|
||||||
|
arg.Image,
|
||||||
arg.UpdatedAt,
|
arg.UpdatedAt,
|
||||||
)
|
)
|
||||||
var i Product
|
var i Product
|
||||||
@ -210,6 +224,7 @@ func (q *Queries) UpdateProduct(ctx context.Context, arg UpdateProductParams) (P
|
|||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ProductCategoryID,
|
&i.ProductCategoryID,
|
||||||
|
&i.Image,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ func createRandomProduct(t *testing.T) (Product, CreateProductParams) {
|
|||||||
PurchasePrice: purchasePrice,
|
PurchasePrice: purchasePrice,
|
||||||
ProductCategoryID: productCategory.ID,
|
ProductCategoryID: productCategory.ID,
|
||||||
Stock: stock,
|
Stock: stock,
|
||||||
|
Image: sql.NullString{Valid: false},
|
||||||
}
|
}
|
||||||
|
|
||||||
product, err := testQueries.CreateProduct(context.Background(), arg)
|
product, err := testQueries.CreateProduct(context.Background(), arg)
|
||||||
|
Loading…
Reference in New Issue
Block a user