add product image

This commit is contained in:
nochill 2023-04-05 14:04:49 +07:00
parent 9ebacf85aa
commit c7422da71a
9 changed files with 120 additions and 46 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
*.env
*.env
public

View File

@ -3,33 +3,59 @@ package api
import (
"database/sql"
"errors"
"fmt"
"net/http"
"os"
"path/filepath"
"time"
db "git.nochill.in/nochill/naice_pos/db/sqlc"
"git.nochill.in/nochill/naice_pos/token"
"git.nochill.in/nochill/naice_pos/util"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type createProductRequest struct {
Name string `json:"name" binding:"required"`
SellingPrice float64 `json:"selling_price" binding:"required"`
ProductTypeID int16 `json:"product_type_id" binding:"required"`
PurchasePrice float64 `json:"purchase_price" binding:"required"`
ProductCategoryID string `json:"product_category_id" binding:"required"`
Stock float64 `json:"stock" binding:"number"`
Name string `form:"name" binding:"required"`
SellingPrice float64 `form:"selling_price" binding:"required"`
ProductTypeID int16 `form:"product_type_id" binding:"required"`
PurchasePrice float64 `form:"purchase_price" binding:"required"`
ProductCategoryID string `form:"product_category_id" binding:"required"`
Stock float64 `form:"stock" binding:"number"`
}
func (server *Server) createProduct(ctx *gin.Context) {
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, ""))
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 := 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{
MerchantID: authPayload.MerchantID,
Name: req.Name,
@ -38,6 +64,7 @@ func (server *Server) createProduct(ctx *gin.Context) {
PurchasePrice: req.PurchasePrice,
ProductCategoryID: uuid.MustParse(req.ProductCategoryID),
Stock: req.Stock,
Image: sql.NullString{Valid: len(imagePath) > 0, String: imagePath},
}
product, err := server.store.CreateProduct(ctx, arg)
@ -109,19 +136,38 @@ func (server *Server) listProducts(ctx *gin.Context) {
}
type updateProductRequest struct {
ProductID uuid.UUID `json:"product_id" binding:"required"`
Name string `json:"name" binding:"required"`
SellingPrice float64 `json:"selling_price" binding:"required"`
PurchasePrice float64 `json:"purchase_price" binding:"required"`
ProductID uuid.UUID `form:"product_id" binding:"required"`
Name string `form:"name" binding:"required"`
SellingPrice float64 `form:"selling_price" binding:"required"`
PurchasePrice float64 `form:"purchase_price" binding:"required"`
}
func (server *Server) updateProduct(ctx *gin.Context) {
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, ""))
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{
ID: req.ProductID,
Name: req.Name,

View File

@ -2,6 +2,7 @@ package api
import (
"fmt"
"path/filepath"
db "git.nochill.in/nochill/naice_pos/db/sqlc"
"git.nochill.in/nochill/naice_pos/token"
@ -37,6 +38,7 @@ func (server *Server) getRoutes() {
router.POST("/user/login", server.loginUser)
router.POST("/user/merchants", server.createUserMerchant)
router.POST("/user/renew_token", server.renewAccessToken)
router.Static("/public", filepath.Base("public"))
apiRoutes := router.Group("/api").Use(authMiddleware(server.tokenMaker))

View File

@ -0,0 +1 @@
ALTER TABLE product DROP COLUMN IF EXISTS image;

View File

@ -0,0 +1 @@
ALTER TABLE products ADD COLUMN image text;

View File

@ -6,9 +6,10 @@ INSERT INTO products (
product_type_id,
purchase_price,
product_category_id,
image,
stock
) VALUES (
$1, $2, $3, $4, $5, $6, $7
$1, $2, $3, $4, $5, $6, $7, $8
)
RETURNING *;
@ -36,7 +37,12 @@ OFFSET $3;
-- name: UpdateProduct :one
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
RETURNING *;

View File

@ -77,17 +77,18 @@ type Merchant struct {
}
type Product struct {
ID uuid.UUID `json:"id"`
MerchantID uuid.UUID `json:"merchant_id"`
ProductTypeID int16 `json:"product_type_id"`
IndexID int64 `json:"index_id"`
Name string `json:"name"`
SellingPrice float64 `json:"selling_price"`
PurchasePrice float64 `json:"purchase_price"`
Stock float64 `json:"stock"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
ProductCategoryID uuid.UUID `json:"product_category_id"`
ID uuid.UUID `json:"id"`
MerchantID uuid.UUID `json:"merchant_id"`
ProductTypeID int16 `json:"product_type_id"`
IndexID int64 `json:"index_id"`
Name string `json:"name"`
SellingPrice float64 `json:"selling_price"`
PurchasePrice float64 `json:"purchase_price"`
Stock float64 `json:"stock"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
ProductCategoryID uuid.UUID `json:"product_category_id"`
Image sql.NullString `json:"image"`
}
type ProductCategory struct {

View File

@ -20,21 +20,23 @@ INSERT INTO products (
product_type_id,
purchase_price,
product_category_id,
image,
stock
) 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 {
MerchantID uuid.UUID `json:"merchant_id"`
Name string `json:"name"`
SellingPrice float64 `json:"selling_price"`
ProductTypeID int16 `json:"product_type_id"`
PurchasePrice float64 `json:"purchase_price"`
ProductCategoryID uuid.UUID `json:"product_category_id"`
Stock float64 `json:"stock"`
MerchantID uuid.UUID `json:"merchant_id"`
Name string `json:"name"`
SellingPrice float64 `json:"selling_price"`
ProductTypeID int16 `json:"product_type_id"`
PurchasePrice float64 `json:"purchase_price"`
ProductCategoryID uuid.UUID `json:"product_category_id"`
Image sql.NullString `json:"image"`
Stock float64 `json:"stock"`
}
func (q *Queries) CreateProduct(ctx context.Context, arg CreateProductParams) (Product, error) {
@ -45,6 +47,7 @@ func (q *Queries) CreateProduct(ctx context.Context, arg CreateProductParams) (P
arg.ProductTypeID,
arg.PurchasePrice,
arg.ProductCategoryID,
arg.Image,
arg.Stock,
)
var i Product
@ -60,6 +63,7 @@ func (q *Queries) CreateProduct(ctx context.Context, arg CreateProductParams) (P
&i.CreatedAt,
&i.UpdatedAt,
&i.ProductCategoryID,
&i.Image,
)
return i, err
}
@ -74,7 +78,7 @@ func (q *Queries) DeleteProduct(ctx context.Context, id uuid.UUID) error {
}
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
`
@ -93,12 +97,13 @@ func (q *Queries) GetProduct(ctx context.Context, id uuid.UUID) (Product, error)
&i.CreatedAt,
&i.UpdatedAt,
&i.ProductCategoryID,
&i.Image,
)
return i, err
}
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
LIMIT 1
FOR NO KEY UPDATE
@ -119,12 +124,13 @@ func (q *Queries) GetStockForUpdateStock(ctx context.Context, id uuid.UUID) (Pro
&i.CreatedAt,
&i.UpdatedAt,
&i.ProductCategoryID,
&i.Image,
)
return i, err
}
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
ORDER BY index_id
LIMIT $2
@ -158,6 +164,7 @@ func (q *Queries) ListProducts(ctx context.Context, arg ListProductsParams) ([]P
&i.CreatedAt,
&i.UpdatedAt,
&i.ProductCategoryID,
&i.Image,
); err != nil {
return nil, err
}
@ -174,18 +181,24 @@ func (q *Queries) ListProducts(ctx context.Context, arg ListProductsParams) ([]P
const updateProduct = `-- name: UpdateProduct :one
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
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 {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
SellingPrice float64 `json:"selling_price"`
PurchasePrice float64 `json:"purchase_price"`
ProductCategoryID uuid.UUID `json:"product_category_id"`
UpdatedAt sql.NullTime `json:"updated_at"`
ID uuid.UUID `json:"id"`
Name string `json:"name"`
SellingPrice float64 `json:"selling_price"`
PurchasePrice float64 `json:"purchase_price"`
ProductCategoryID uuid.UUID `json:"product_category_id"`
Image sql.NullString `json:"image"`
UpdatedAt sql.NullTime `json:"updated_at"`
}
func (q *Queries) UpdateProduct(ctx context.Context, arg UpdateProductParams) (Product, error) {
@ -195,6 +208,7 @@ func (q *Queries) UpdateProduct(ctx context.Context, arg UpdateProductParams) (P
arg.SellingPrice,
arg.PurchasePrice,
arg.ProductCategoryID,
arg.Image,
arg.UpdatedAt,
)
var i Product
@ -210,6 +224,7 @@ func (q *Queries) UpdateProduct(ctx context.Context, arg UpdateProductParams) (P
&i.CreatedAt,
&i.UpdatedAt,
&i.ProductCategoryID,
&i.Image,
)
return i, err
}

View File

@ -26,6 +26,7 @@ func createRandomProduct(t *testing.T) (Product, CreateProductParams) {
PurchasePrice: purchasePrice,
ProductCategoryID: productCategory.ID,
Stock: stock,
Image: sql.NullString{Valid: false},
}
product, err := testQueries.CreateProduct(context.Background(), arg)