Add User Partner and Product
This commit is contained in:
parent
67f1dbc850
commit
8a23e72230
@ -30,6 +30,3 @@ deploy_to_staging:
|
||||
- kubectl apply -f k8s/staging/ingress.yaml
|
||||
only:
|
||||
- main
|
||||
|
||||
# tes bintang 4
|
||||
|
||||
|
||||
4
Makefile
4
Makefile
@ -1,9 +1,9 @@
|
||||
PROJECT_NAME = "furtuna-backend"
|
||||
DB_USERNAME := furtuna_admin
|
||||
DB_USERNAME := fortuna_admin
|
||||
DB_PASSWORD := Z4G827t9428QFQ%5ESZXW%2343dB%25%214Bmh80
|
||||
DB_HOST := 103.96.146.124
|
||||
DB_PORT := 1960
|
||||
DB_NAME := furtuna-staging
|
||||
DB_NAME := fortuna-staging
|
||||
|
||||
DB_URL = postgres://$(DB_USERNAME):$(DB_PASSWORD)@$(DB_HOST):$(DB_PORT)/$(DB_NAME)?sslmode=disable
|
||||
|
||||
|
||||
1
furtuna-frontend
Submodule
1
furtuna-frontend
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 19af799abdd523522fad579044d55f5d764f87a3
|
||||
@ -72,6 +72,9 @@ func (s *ServiceException) MapErrorsToHTTPCode() int {
|
||||
case errInvalidLogin:
|
||||
return http.StatusBadRequest
|
||||
|
||||
case errUserIsNotFound:
|
||||
return http.StatusBadRequest
|
||||
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
@ -89,6 +92,9 @@ func (s *ServiceException) MapErrorsToCode() Code {
|
||||
case errBadRequest:
|
||||
return BadRequest
|
||||
|
||||
case errUserIsNotFound:
|
||||
return BadRequest
|
||||
|
||||
default:
|
||||
return ServerError
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ type Context interface {
|
||||
|
||||
RequestedBy() int64
|
||||
IsSuperAdmin() bool
|
||||
GetPartnerID() *int64
|
||||
}
|
||||
|
||||
type MyContextImpl struct {
|
||||
@ -20,7 +21,7 @@ type MyContextImpl struct {
|
||||
|
||||
requestedBy int64
|
||||
requestID string
|
||||
branchID int64
|
||||
partnerID int64
|
||||
roleID int
|
||||
}
|
||||
|
||||
@ -32,11 +33,18 @@ func (m *MyContextImpl) IsSuperAdmin() bool {
|
||||
return m.roleID == int(role.SuperAdmin)
|
||||
}
|
||||
|
||||
func (m *MyContextImpl) GetPartnerID() *int64 {
|
||||
if m.partnerID != 0 {
|
||||
return &m.partnerID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewMyContext(parent context.Context, claims *entity.JWTAuthClaims) (*MyContextImpl, error) {
|
||||
return &MyContextImpl{
|
||||
Context: parent,
|
||||
requestedBy: claims.UserID,
|
||||
branchID: claims.BranchID,
|
||||
partnerID: claims.PartnerID,
|
||||
roleID: claims.Role,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@ type Role int64
|
||||
|
||||
const (
|
||||
SuperAdmin Role = 1
|
||||
BranchAdmin Role = 2
|
||||
CasheerAdmin Role = 3
|
||||
Admin Role = 2
|
||||
PartnerAdmin Role = 3
|
||||
SiteAdmin Role = 4
|
||||
Casheer Role = 5
|
||||
)
|
||||
|
||||
@ -3,8 +3,8 @@ package studio
|
||||
type StudioStatus string
|
||||
|
||||
const (
|
||||
Active StudioStatus = "Active"
|
||||
Inactive StudioStatus = "Inactive"
|
||||
Active StudioStatus = "active"
|
||||
Inactive StudioStatus = "inactive"
|
||||
)
|
||||
|
||||
func (b StudioStatus) toString() string {
|
||||
|
||||
@ -24,8 +24,9 @@ type UserDB struct {
|
||||
NIK string `gorm:"column:nik" json:"nik"`
|
||||
RoleID int64 `gorm:"column:role_id" json:"role_id"`
|
||||
RoleName string `gorm:"column:role_name" json:"role_name"`
|
||||
BranchID *int64 `gorm:"column:partner_id" json:"partner_id"`
|
||||
BranchName string `gorm:"column:partner_name" json:"partner_name"`
|
||||
PartnerID *int64 `gorm:"column:partner_id" json:"partner_id"`
|
||||
PartnerName string `gorm:"column:partner_name" json:"partner_name"`
|
||||
PartnerStatus string `gorm:"column:partner_status" json:"partner_status"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
DeletedAt *time.Time `gorm:"column:deleted_at" json:"deleted_at"`
|
||||
@ -47,8 +48,8 @@ func (u *UserDB) ToUser() *User {
|
||||
UpdatedAt: u.UpdatedAt,
|
||||
RoleID: role.Role(u.RoleID),
|
||||
RoleName: u.RoleName,
|
||||
PartnerID: u.BranchID,
|
||||
BranchName: u.BranchName,
|
||||
PartnerID: u.PartnerID,
|
||||
PartnerName: u.PartnerName,
|
||||
}
|
||||
|
||||
return userEntity
|
||||
@ -63,7 +64,7 @@ func (u *UserDB) ToUserRoleDB() *UserRoleDB {
|
||||
ID: 0,
|
||||
UserID: u.ID,
|
||||
RoleID: u.RoleID,
|
||||
PartnerID: u.BranchID,
|
||||
PartnerID: u.PartnerID,
|
||||
CreatedAt: u.CreatedAt,
|
||||
UpdatedAt: u.UpdatedAt,
|
||||
}
|
||||
@ -81,8 +82,9 @@ func (u *UserDB) ToUserAuthenticate(signedToken string) *AuthenticateUser {
|
||||
Name: u.Name,
|
||||
RoleID: role.Role(u.RoleID),
|
||||
RoleName: u.RoleName,
|
||||
BranchID: u.BranchID,
|
||||
BranchName: u.BranchName,
|
||||
PartnerID: u.PartnerID,
|
||||
PartnerName: u.PartnerName,
|
||||
PartnerStatus: u.PartnerStatus,
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +118,7 @@ func (u *UserDB) ToUpdatedUser(req User) error {
|
||||
}
|
||||
|
||||
if *req.PartnerID > 0 {
|
||||
u.BranchID = req.PartnerID
|
||||
u.PartnerID = req.PartnerID
|
||||
}
|
||||
|
||||
if req.RoleID > 0 {
|
||||
|
||||
@ -7,6 +7,6 @@ type JWTAuthClaims struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Role int `json:"role"`
|
||||
BranchID int64 `json:"branch_id"`
|
||||
PartnerID int64 `json:"partner_id"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
@ -1,19 +1,42 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"furtuna-be/internal/constants/role"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CreatePartnerRequest struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Address string `json:"address"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
FullName string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
NIK string `json:"nik"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
BankName string `json:"bank_name"`
|
||||
BankAccountNumber string `json:"bank_account_number"`
|
||||
BankAccountHolderName string `json:"bank_account_holder_name"`
|
||||
}
|
||||
|
||||
type Partner struct {
|
||||
ID int64
|
||||
Name string
|
||||
Status string
|
||||
Address string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
CreatedBy int64
|
||||
UpdatedBy int64
|
||||
ID int64 `gorm:"primaryKey;autoIncrement;column:id"`
|
||||
Name string `gorm:"type:varchar(255);not null;column:name"`
|
||||
Status string `gorm:"type:varchar(50);column:status"`
|
||||
LicenseExpiredDate *time.Time `gorm:"type:date;column:license_expired_date"`
|
||||
Address string `gorm:"type:varchar(255);column:address"`
|
||||
BankName string `gorm:"type:varchar(255);column:bank_name"`
|
||||
BankAccountNumber string `gorm:"type:varchar(50);column:bank_account_number"`
|
||||
BankAccountHolderName string `gorm:"type:varchar(255);column:bank_account_holder_name"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"`
|
||||
DeletedAt *time.Time `gorm:"column:deleted_at"`
|
||||
CreatedBy int64 `gorm:"type:int;column:created_by"`
|
||||
UpdatedBy int64 `gorm:"type:int;column:updated_by"`
|
||||
}
|
||||
|
||||
func (Partner) TableName() string {
|
||||
return "partners"
|
||||
}
|
||||
|
||||
type PartnerSearch struct {
|
||||
@ -80,3 +103,46 @@ func (o *PartnerDB) SetDeleted(updatedBy int64) {
|
||||
o.DeletedAt = ¤tTime
|
||||
o.UpdatedBy = updatedBy
|
||||
}
|
||||
|
||||
func (c *CreatePartnerRequest) ToUserAdmin(partnerID int64) *User {
|
||||
return &User{
|
||||
Name: c.FullName,
|
||||
Password: c.Password,
|
||||
Email: c.Email,
|
||||
NIK: c.NIK,
|
||||
Status: "active",
|
||||
RoleID: role.PartnerAdmin,
|
||||
PartnerID: &partnerID,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *CreatePartnerRequest) ToPartnerDB(createdBy int64) *PartnerDB {
|
||||
twoDays := 48 * time.Hour
|
||||
licenseExpiredDate := time.Now().Add(twoDays)
|
||||
|
||||
return &PartnerDB{
|
||||
Partner: Partner{
|
||||
Name: e.Name,
|
||||
Status: "inactive",
|
||||
Address: e.Address,
|
||||
CreatedBy: createdBy,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
BankAccountHolderName: e.BankAccountHolderName,
|
||||
BankAccountNumber: e.BankAccountNumber,
|
||||
BankName: e.BankName,
|
||||
LicenseExpiredDate: &licenseExpiredDate,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (e *CreatePartnerRequest) ToWallet(partnerID int64) *Wallet {
|
||||
return &Wallet{
|
||||
PartnerID: partnerID,
|
||||
Balance: 0,
|
||||
Currency: "IDR",
|
||||
Status: "active",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,20 +6,25 @@ import (
|
||||
)
|
||||
|
||||
type Product struct {
|
||||
ID int64
|
||||
Name string
|
||||
Type product.ProductType
|
||||
Price float64
|
||||
Status product.ProductStatus
|
||||
Description string
|
||||
Image string
|
||||
BranchID int64
|
||||
StockQty int64
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time
|
||||
CreatedBy int64
|
||||
UpdatedBy int64
|
||||
ID int64 `gorm:"primaryKey;autoIncrement;column:id"`
|
||||
PartnerID int64 `gorm:"type:int;column:partner_id"`
|
||||
SiteID int64 `gorm:"type:int;column:site_id"`
|
||||
Name string `gorm:"type:varchar(255);not null;column:name"`
|
||||
Type string `gorm:"type:varchar;column:type"`
|
||||
Price float64 `gorm:"type:decimal;column:price"`
|
||||
IsWeekendTicket bool `gorm:"type:bool;column:is_weekend_ticket"`
|
||||
IsSeasonTicket bool `gorm:"type:bool;column:is_season_ticket"`
|
||||
Status string `gorm:"type:varchar;column:status"`
|
||||
Description string `gorm:"type:varchar(255);not null;column:description"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"`
|
||||
DeletedAt *time.Time `gorm:"column:deleted_at"`
|
||||
CreatedBy int64 `gorm:"type:int;column:created_by"`
|
||||
UpdatedBy int64 `gorm:"type:int;column:updated_by"`
|
||||
}
|
||||
|
||||
func (Product) TableName() string {
|
||||
return "products"
|
||||
}
|
||||
|
||||
type ProductSearch struct {
|
||||
@ -56,9 +61,7 @@ func (e *ProductDB) ToProduct() *Product {
|
||||
Price: e.Price,
|
||||
Status: e.Status,
|
||||
Description: e.Description,
|
||||
Image: e.Image,
|
||||
BranchID: e.BranchID,
|
||||
StockQty: e.StockQty,
|
||||
PartnerID: e.PartnerID,
|
||||
CreatedAt: e.CreatedAt,
|
||||
UpdatedAt: e.UpdatedAt,
|
||||
DeletedAt: e.DeletedAt,
|
||||
@ -97,14 +100,6 @@ func (o *ProductDB) ToUpdatedProduct(updatedby int64, req Product) {
|
||||
if req.Description != "" {
|
||||
o.Description = req.Description
|
||||
}
|
||||
|
||||
if req.Image != "" {
|
||||
o.Image = req.Image
|
||||
}
|
||||
|
||||
if req.StockQty > 0 {
|
||||
o.StockQty = req.StockQty
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ProductDB) SetDeleted(updatedby int64) {
|
||||
|
||||
145
internal/entity/sites.go
Normal file
145
internal/entity/sites.go
Normal file
@ -0,0 +1,145 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Site struct {
|
||||
ID int64 `gorm:"primaryKey;autoIncrement;column:id"`
|
||||
Name string `gorm:"type:varchar(255);not null;column:name"`
|
||||
PartnerID int64 `gorm:"type:int;column:partner_id"`
|
||||
Image string `gorm:"type:varchar;column:image"`
|
||||
Address string `gorm:"type:varchar;column:address"`
|
||||
LocationLink string `gorm:"type:varchar;column:location_link"`
|
||||
Description string `gorm:"type:varchar;column:description"`
|
||||
Highlight string `gorm:"type:varchar;column:highlight"`
|
||||
ContactPerson string `gorm:"type:varchar;column:contact_person"`
|
||||
TnC string `gorm:"type:varchar;column:tnc"`
|
||||
AdditionalInfo string `gorm:"type:varchar;column:additional_info"`
|
||||
Status string `gorm:"type:varchar;column:status"`
|
||||
IsSeasonTicket bool `gorm:"type:bool;column:is_season_ticket"`
|
||||
IsDiscountActive bool `gorm:"type:bool;column:is_discount_active"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"`
|
||||
DeletedAt *time.Time `gorm:"column:deleted_at"`
|
||||
CreatedBy int64 `gorm:"type:int;column:created_by"`
|
||||
UpdatedBy int64 `gorm:"type:int;column:updated_by"`
|
||||
Products []Product `gorm:"foreignKey:SiteID;constraint:OnDelete:CASCADE;"`
|
||||
}
|
||||
|
||||
type SiteSearch struct {
|
||||
Search string
|
||||
Name string
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
type SiteList []*SiteDB
|
||||
|
||||
type SiteDB struct {
|
||||
Site
|
||||
}
|
||||
|
||||
func (s *Site) ToSiteDB() *SiteDB {
|
||||
return &SiteDB{
|
||||
Site: *s,
|
||||
}
|
||||
}
|
||||
|
||||
func (SiteDB) TableName() string {
|
||||
return "sites"
|
||||
}
|
||||
|
||||
func (e *SiteDB) ToSite() *Site {
|
||||
return &Site{
|
||||
ID: e.ID,
|
||||
Name: e.Name,
|
||||
PartnerID: e.PartnerID,
|
||||
Image: e.Image,
|
||||
Address: e.Address,
|
||||
LocationLink: e.LocationLink,
|
||||
Description: e.Description,
|
||||
Highlight: e.Highlight,
|
||||
ContactPerson: e.ContactPerson,
|
||||
TnC: e.TnC,
|
||||
AdditionalInfo: e.AdditionalInfo,
|
||||
Status: e.Status,
|
||||
IsSeasonTicket: e.IsSeasonTicket,
|
||||
IsDiscountActive: e.IsDiscountActive,
|
||||
CreatedAt: e.CreatedAt,
|
||||
UpdatedAt: e.UpdatedAt,
|
||||
DeletedAt: e.DeletedAt,
|
||||
CreatedBy: e.CreatedBy,
|
||||
UpdatedBy: e.UpdatedBy,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SiteList) ToSiteList() []*Site {
|
||||
var sites []*Site
|
||||
for _, site := range *s {
|
||||
sites = append(sites, site.ToSite())
|
||||
}
|
||||
return sites
|
||||
}
|
||||
|
||||
func (o *SiteDB) ToUpdatedSite(updatedBy int64, req Site) {
|
||||
o.UpdatedBy = updatedBy
|
||||
|
||||
if req.Name != "" {
|
||||
o.Name = req.Name
|
||||
}
|
||||
|
||||
if req.PartnerID != 0 {
|
||||
o.PartnerID = req.PartnerID
|
||||
}
|
||||
|
||||
if req.Image != "" {
|
||||
o.Image = req.Image
|
||||
}
|
||||
|
||||
if req.Address != "" {
|
||||
o.Address = req.Address
|
||||
}
|
||||
|
||||
if req.LocationLink != "" {
|
||||
o.LocationLink = req.LocationLink
|
||||
}
|
||||
|
||||
if req.Description != "" {
|
||||
o.Description = req.Description
|
||||
}
|
||||
|
||||
if req.Highlight != "" {
|
||||
o.Highlight = req.Highlight
|
||||
}
|
||||
|
||||
if req.ContactPerson != "" {
|
||||
o.ContactPerson = req.ContactPerson
|
||||
}
|
||||
|
||||
if req.TnC != "" {
|
||||
o.TnC = req.TnC
|
||||
}
|
||||
|
||||
if req.AdditionalInfo != "" {
|
||||
o.AdditionalInfo = req.AdditionalInfo
|
||||
}
|
||||
|
||||
if req.Status != "" {
|
||||
o.Status = req.Status
|
||||
}
|
||||
|
||||
if req.IsSeasonTicket {
|
||||
o.IsSeasonTicket = req.IsSeasonTicket
|
||||
}
|
||||
|
||||
if req.IsDiscountActive {
|
||||
o.IsDiscountActive = req.IsDiscountActive
|
||||
}
|
||||
}
|
||||
|
||||
func (o *SiteDB) SetDeleted(updatedBy int64) {
|
||||
currentTime := time.Now()
|
||||
o.DeletedAt = ¤tTime
|
||||
o.UpdatedBy = updatedBy
|
||||
}
|
||||
@ -21,7 +21,7 @@ type User struct {
|
||||
RoleID role.Role
|
||||
RoleName string
|
||||
PartnerID *int64
|
||||
BranchName string
|
||||
PartnerName string
|
||||
}
|
||||
|
||||
type AuthenticateUser struct {
|
||||
@ -29,8 +29,9 @@ type AuthenticateUser struct {
|
||||
Name string
|
||||
RoleID role.Role
|
||||
RoleName string
|
||||
BranchID *int64
|
||||
BranchName string
|
||||
PartnerID *int64
|
||||
PartnerName string
|
||||
PartnerStatus string
|
||||
}
|
||||
|
||||
type UserRoleDB struct {
|
||||
@ -53,7 +54,7 @@ func (u *User) ToUserDB(createdBy int64) (*UserDB, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if u.RoleID == role.BranchAdmin && u.PartnerID == nil {
|
||||
if u.RoleID == role.Admin && u.PartnerID == nil {
|
||||
return nil, errors.New("invalid request")
|
||||
}
|
||||
|
||||
@ -62,7 +63,7 @@ func (u *User) ToUserDB(createdBy int64) (*UserDB, error) {
|
||||
Email: u.Email,
|
||||
Password: hashedPassword,
|
||||
RoleID: int64(u.RoleID),
|
||||
BranchID: u.PartnerID,
|
||||
PartnerID: u.PartnerID,
|
||||
Status: userstatus.Active,
|
||||
CreatedBy: createdBy,
|
||||
}, nil
|
||||
|
||||
17
internal/entity/wallet.go
Normal file
17
internal/entity/wallet.go
Normal file
@ -0,0 +1,17 @@
|
||||
package entity
|
||||
|
||||
import "time"
|
||||
|
||||
type Wallet struct {
|
||||
ID int64 `gorm:"primaryKey;autoIncrement;column:id"`
|
||||
PartnerID int64 `gorm:"type:int;not null;column:partner_id"`
|
||||
Balance float64 `gorm:"type:decimal(18,2);not null;default:0.00;column:balance"`
|
||||
Currency string `gorm:"type:varchar(3);not null;column:currency"`
|
||||
Status string `gorm:"type:varchar(50);column:status"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"`
|
||||
}
|
||||
|
||||
func (Wallet) TableName() string {
|
||||
return "wallets"
|
||||
}
|
||||
@ -51,18 +51,19 @@ func (h *AuthHandler) AuthLogin(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var branch *response.Branch
|
||||
var partner *response.Partner
|
||||
|
||||
if authUser.RoleID != role.SuperAdmin {
|
||||
branch = &response.Branch{
|
||||
ID: authUser.BranchID,
|
||||
Name: authUser.BranchName,
|
||||
partner = &response.Partner{
|
||||
ID: authUser.PartnerID,
|
||||
Name: authUser.PartnerName,
|
||||
Status: authUser.PartnerStatus,
|
||||
}
|
||||
}
|
||||
|
||||
resp := response.LoginResponse{
|
||||
Token: authUser.Token,
|
||||
Branch: branch,
|
||||
Partner: partner,
|
||||
Name: authUser.Name,
|
||||
Role: response.Role{
|
||||
ID: int64(authUser.RoleID),
|
||||
|
||||
@ -51,7 +51,7 @@ func NewHandler(service services.Partner) *Handler {
|
||||
func (h *Handler) Create(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
var req request.Partner
|
||||
var req request.CreatePartnerRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
|
||||
@ -246,9 +246,6 @@ func (h *Handler) toProductResponse(resp *entity.Product) response.Product {
|
||||
Price: resp.Price,
|
||||
Status: resp.Status,
|
||||
Description: resp.Description,
|
||||
Image: resp.Image,
|
||||
BranchID: resp.BranchID,
|
||||
StockQty: resp.StockQty,
|
||||
CreatedAt: resp.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: resp.CreatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
299
internal/handlers/http/sites/sites.go
Normal file
299
internal/handlers/http/sites/sites.go
Normal file
@ -0,0 +1,299 @@
|
||||
package site
|
||||
|
||||
import (
|
||||
"furtuna-be/internal/common/errors"
|
||||
"furtuna-be/internal/entity"
|
||||
"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"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
service services.Site
|
||||
}
|
||||
|
||||
func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
||||
route := group.Group("/site")
|
||||
|
||||
route.POST("/", jwt, h.Create)
|
||||
route.GET("/list", jwt, h.GetAll)
|
||||
route.PUT("/:id", jwt, h.Update)
|
||||
route.GET("/:id", jwt, h.GetByID)
|
||||
route.DELETE("/:id", jwt, h.Delete)
|
||||
}
|
||||
|
||||
func NewHandler(service services.Site) *Handler {
|
||||
return &Handler{
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
// Create handles the creation of a new Site.
|
||||
// @Summary Create a new Site
|
||||
// @Description Create a new Site based on the provided data.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Authorization header string true "JWT token"
|
||||
// @Param req body request.Site true "New Site details"
|
||||
// @Success 200 {object} response.BaseResponse{data=response.Site} "Site created successfully"
|
||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
||||
// @Router /api/v1/site [post]
|
||||
// @Tags Site APIs
|
||||
func (h *Handler) Create(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
var req request.Site
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.IsSuperAdmin() {
|
||||
req.PartnerID = ctx.GetPartnerID()
|
||||
}
|
||||
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(req); err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := h.service.Create(ctx, req.ToEntity(ctx.RequestedBy()))
|
||||
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: h.toSiteResponse(res),
|
||||
})
|
||||
}
|
||||
|
||||
// Update handles the update of an existing Site.
|
||||
// @Summary Update an existing Site
|
||||
// @Description Update the details of an existing Site based on the provided ID.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Authorization header string true "JWT token"
|
||||
// @Param id path int64 true "Site ID to update"
|
||||
// @Param req body request.Site true "Updated Site details"
|
||||
// @Success 200 {object} response.BaseResponse{data=response.Site} "Site updated successfully"
|
||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
||||
// @Router /api/v1/site/{id} [put]
|
||||
// @Tags Site APIs
|
||||
func (h *Handler) Update(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
id := c.Param("id")
|
||||
|
||||
SiteID, err := strconv.ParseInt(id, 10, 64)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req request.Site
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(req); err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
updatedSite, err := h.service.Update(ctx, SiteID, req.ToEntity(ctx.RequestedBy()))
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: h.toSiteResponse(updatedSite),
|
||||
})
|
||||
}
|
||||
|
||||
// GetAll retrieves a list of Sites.
|
||||
// @Summary Get a list of Sites
|
||||
// @Description Get a paginated list of Sites based on query 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 "Offset for pagination (default 0)"
|
||||
// @Success 200 {object} response.BaseResponse{data=response.SiteList} "List of Sites"
|
||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
||||
// @Router /api/v1/site/list [get]
|
||||
// @Tags Site APIs
|
||||
func (h *Handler) GetAll(c *gin.Context) {
|
||||
var req request.SiteParam
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
Sites, total, err := h.service.GetAll(c.Request.Context(), req.ToEntity())
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: h.toSiteResponseList(Sites, int64(total), req),
|
||||
})
|
||||
}
|
||||
|
||||
// Delete handles the deletion of a Site by ID.
|
||||
// @Summary Delete a Site by ID
|
||||
// @Description Delete a Site based on the provided ID.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Authorization header string true "JWT token"
|
||||
// @Param id path int64 true "Site ID to delete"
|
||||
// @Success 200 {object} response.BaseResponse "Site deleted successfully"
|
||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
||||
// @Router /api/v1/site/{id} [delete]
|
||||
// @Tags Site APIs
|
||||
func (h *Handler) Delete(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
id := c.Param("id")
|
||||
|
||||
// Parse the ID into a uint
|
||||
SiteID, err := strconv.ParseInt(id, 10, 64)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.Delete(ctx, SiteID)
|
||||
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: nil,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByID retrieves details of a specific Site by ID.
|
||||
// @Summary Get details of a Site by ID
|
||||
// @Description Get details of a Site based on the provided ID.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Authorization header string true "JWT token"
|
||||
// @Param id path int64 true "Site ID to retrieve"
|
||||
// @Success 200 {object} response.BaseResponse{data=response.Site} "Site details"
|
||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
||||
// @Router /api/v1/site/{id} [get]
|
||||
// @Tags Site APIs
|
||||
func (h *Handler) GetByID(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
// Parse the ID into a uint
|
||||
SiteID, err := strconv.ParseInt(id, 10, 64)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := h.service.GetByID(c.Request.Context(), SiteID)
|
||||
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.toSiteResponse(res),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) toSiteResponse(resp *entity.Site) response.Site {
|
||||
return response.Site{
|
||||
ID: &resp.ID,
|
||||
Name: resp.Name,
|
||||
PartnerID: resp.PartnerID,
|
||||
Image: resp.Image,
|
||||
Address: resp.Address,
|
||||
LocationLink: resp.LocationLink,
|
||||
Description: resp.Description,
|
||||
Highlight: resp.Highlight,
|
||||
ContactPerson: resp.ContactPerson,
|
||||
TnC: resp.TnC,
|
||||
AdditionalInfo: resp.AdditionalInfo,
|
||||
Status: resp.Status,
|
||||
IsSeasonTicket: resp.IsSeasonTicket,
|
||||
IsDiscountActive: resp.IsDiscountActive,
|
||||
CreatedAt: resp.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: resp.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) toSiteResponseList(resp []*entity.Site, total int64, req request.SiteParam) response.SiteList {
|
||||
var Sites []response.Site
|
||||
for _, b := range resp {
|
||||
Sites = append(Sites, h.toSiteResponse(b))
|
||||
}
|
||||
|
||||
return response.SiteList{
|
||||
Sites: Sites,
|
||||
Total: total,
|
||||
Limit: req.Limit,
|
||||
Offset: req.Offset,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) toProductResponseList(products []entity.Product) []response.Product {
|
||||
var res []response.Product
|
||||
for _, product := range products {
|
||||
res = append(res, response.Product{
|
||||
ID: product.ID,
|
||||
PartnerID: product.PartnerID,
|
||||
SiteID: product.SiteID,
|
||||
Name: product.Name,
|
||||
Type: product.Type,
|
||||
Price: product.Price,
|
||||
IsWeekendTicket: product.IsWeekendTicket,
|
||||
IsSeasonTicket: product.IsSeasonTicket,
|
||||
Status: product.Status,
|
||||
Description: product.Description,
|
||||
CreatedAt: product.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: product.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
return res
|
||||
}
|
||||
@ -56,13 +56,15 @@ func (h *Handler) Create(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
req.PartnerID = ctx.GetPartnerID()
|
||||
if err := req.Validate(); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorInvalidRequest)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := h.service.Create(ctx, req.ToEntity())
|
||||
ctx.IsSuperAdmin()
|
||||
|
||||
res, err := h.service.Create(ctx, req.ToEntity())
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
@ -267,7 +269,7 @@ func (h *Handler) toUserResponse(resp *entity.User) response.User {
|
||||
RoleID: int64(resp.RoleID),
|
||||
RoleName: resp.RoleName,
|
||||
PartnerID: resp.PartnerID,
|
||||
BranchName: resp.BranchName,
|
||||
PartnerName: resp.PartnerName,
|
||||
CreatedAt: resp.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: resp.CreatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
@ -26,6 +26,36 @@ type Partner struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type CreatePartnerRequest struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Address string `json:"address"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
FullName string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
NIK string `json:"nik"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
BankName string `json:"bank_name"`
|
||||
BankAccountNumber string `json:"bank_account_number"`
|
||||
BankAccountHolderName string `json:"bank_account_holder_name"`
|
||||
}
|
||||
|
||||
func (e *CreatePartnerRequest) ToEntity() *entity.CreatePartnerRequest {
|
||||
return &entity.CreatePartnerRequest{
|
||||
Name: e.Name,
|
||||
Address: e.Address,
|
||||
Username: e.Username,
|
||||
FullName: e.FullName,
|
||||
Email: e.Email,
|
||||
Password: e.Password,
|
||||
NIK: e.NIK,
|
||||
PhoneNumber: e.PhoneNumber,
|
||||
BankName: e.BankName,
|
||||
BankAccountNumber: e.BankAccountNumber,
|
||||
BankAccountHolderName: e.BankAccountHolderName,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Partner) ToEntity() *entity.Partner {
|
||||
return &entity.Partner{
|
||||
Name: e.Name,
|
||||
|
||||
@ -28,14 +28,15 @@ func (p *ProductParam) ToEntity() entity.ProductSearch {
|
||||
}
|
||||
|
||||
type Product struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
PartnerID int64 `json:"partner_id"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type product.ProductType `json:"type" validate:"required"`
|
||||
Type string `json:"type"`
|
||||
Price float64 `json:"price" validate:"required"`
|
||||
Status product.ProductStatus `json:"status" validate:"required"`
|
||||
Description string `json:"description" `
|
||||
Image string `json:"image" `
|
||||
BranchID int64 `json:"branch_id" validate:"required"`
|
||||
StockQty int64 `json:"stock_qty" `
|
||||
IsWeekendTicket bool `json:"is_weekend_ticket"`
|
||||
IsSeasonTicket bool `json:"is_season_ticket"`
|
||||
Status string `json:"status"`
|
||||
Description string `json:"description" validate:"required"`
|
||||
}
|
||||
|
||||
func (e *Product) ToEntity() *entity.Product {
|
||||
@ -45,8 +46,5 @@ func (e *Product) ToEntity() *entity.Product {
|
||||
Price: e.Price,
|
||||
Status: e.Status,
|
||||
Description: e.Description,
|
||||
Image: e.Image,
|
||||
BranchID: e.BranchID,
|
||||
StockQty: e.StockQty,
|
||||
}
|
||||
}
|
||||
|
||||
75
internal/handlers/request/site.go
Normal file
75
internal/handlers/request/site.go
Normal file
@ -0,0 +1,75 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"furtuna-be/internal/entity"
|
||||
)
|
||||
|
||||
type Site struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
PartnerID *int64 `json:"partner_id"`
|
||||
Image string `json:"image"`
|
||||
Address string `json:"address"`
|
||||
LocationLink string `json:"location_link"`
|
||||
Description string `json:"description"`
|
||||
Highlight string `json:"highlight"`
|
||||
ContactPerson string `json:"contact_person"`
|
||||
TnC string `json:"tnc"`
|
||||
AdditionalInfo string `json:"additional_info"`
|
||||
Status string `json:"status"`
|
||||
IsSeasonTicket bool `json:"is_season_ticket"`
|
||||
IsDiscountActive bool `json:"is_discount_active"`
|
||||
Products []Product `json:"products"`
|
||||
}
|
||||
|
||||
func (r *Site) ToEntity(createdBy int64) *entity.Site {
|
||||
var products []entity.Product
|
||||
for _, p := range r.Products {
|
||||
products = append(products, entity.Product{
|
||||
ID: p.ID,
|
||||
PartnerID: *r.PartnerID,
|
||||
Name: p.Name,
|
||||
Type: p.Type,
|
||||
Price: p.Price,
|
||||
IsWeekendTicket: p.IsWeekendTicket,
|
||||
IsSeasonTicket: p.IsSeasonTicket,
|
||||
Status: p.Status,
|
||||
Description: p.Description,
|
||||
CreatedBy: createdBy,
|
||||
})
|
||||
}
|
||||
|
||||
return &entity.Site{
|
||||
ID: r.ID,
|
||||
Name: r.Name,
|
||||
PartnerID: *r.PartnerID,
|
||||
Image: r.Image,
|
||||
Address: r.Address,
|
||||
LocationLink: r.LocationLink,
|
||||
Description: r.Description,
|
||||
Highlight: r.Highlight,
|
||||
ContactPerson: r.ContactPerson,
|
||||
TnC: r.TnC,
|
||||
AdditionalInfo: r.AdditionalInfo,
|
||||
Status: r.Status,
|
||||
IsSeasonTicket: r.IsSeasonTicket,
|
||||
IsDiscountActive: r.IsDiscountActive,
|
||||
Products: products,
|
||||
}
|
||||
}
|
||||
|
||||
type SiteParam struct {
|
||||
Search string `form:"search"`
|
||||
Name string `form:"name"`
|
||||
Limit int `form:"limit,default=10"`
|
||||
Offset int `form:"offset,default=0"`
|
||||
}
|
||||
|
||||
func (r *SiteParam) ToEntity() entity.SiteSearch {
|
||||
return entity.SiteSearch{
|
||||
Search: r.Search,
|
||||
Name: r.Name,
|
||||
Limit: r.Limit,
|
||||
Offset: r.Offset,
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,7 @@ type LoginResponse struct {
|
||||
Token string `json:"token"`
|
||||
Name string `json:"name"`
|
||||
Role Role `json:"role"`
|
||||
Branch *Branch `json:"branch"`
|
||||
Partner *Partner `json:"partner"`
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
|
||||
@ -4,9 +4,9 @@ type Partner struct {
|
||||
ID *int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Address string `json:"address"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Address string `json:"address,omitempty"`
|
||||
CreatedAt string `json:"created_at,omitempty"`
|
||||
UpdatedAt string `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
type PartnerList struct {
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
package response
|
||||
|
||||
import "furtuna-be/internal/constants/product"
|
||||
|
||||
type Product struct {
|
||||
ID int64 `json:"id"`
|
||||
PartnerID int64 `json:"partner_id"`
|
||||
SiteID int64 `json:"site_id"`
|
||||
Name string `json:"name"`
|
||||
Type product.ProductType `json:"type"`
|
||||
Type string `json:"type"`
|
||||
Price float64 `json:"price"`
|
||||
Status product.ProductStatus `json:"status"`
|
||||
Description string `json:"description" `
|
||||
Image string `json:"image" `
|
||||
BranchID int64 `json:"branch_id"`
|
||||
StockQty int64 `json:"stock_qty"`
|
||||
IsWeekendTicket bool `json:"is_weekend_ticket"`
|
||||
IsSeasonTicket bool `json:"is_season_ticket"`
|
||||
Status string `json:"status"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
27
internal/handlers/response/site.go
Normal file
27
internal/handlers/response/site.go
Normal file
@ -0,0 +1,27 @@
|
||||
package response
|
||||
|
||||
type Site struct {
|
||||
ID *int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PartnerID int64 `json:"partner_id"`
|
||||
Image string `json:"image"`
|
||||
Address string `json:"address"`
|
||||
LocationLink string `json:"location_link"`
|
||||
Description string `json:"description"`
|
||||
Highlight string `json:"highlight"`
|
||||
ContactPerson string `json:"contact_person"`
|
||||
TnC string `json:"tnc"`
|
||||
AdditionalInfo string `json:"additional_info"`
|
||||
Status string `json:"status"`
|
||||
IsSeasonTicket bool `json:"is_season_ticket"`
|
||||
IsDiscountActive bool `json:"is_discount_active"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
type SiteList struct {
|
||||
Sites []Site `json:"sites"`
|
||||
Total int64 `json:"total"`
|
||||
Limit int `json:"limit"`
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
@ -8,7 +8,7 @@ type User struct {
|
||||
RoleID int64 `json:"role_id"`
|
||||
RoleName string `json:"role_name"`
|
||||
PartnerID *int64 `json:"partner_id"`
|
||||
BranchName string `json:"partner_name"`
|
||||
PartnerName string `json:"partner_name"`
|
||||
CreatedAt string `json:"created_at,omitempty"`
|
||||
UpdatedAt string `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
@ -27,13 +26,17 @@ func (r *AuthRepository) CheckExistsUserAccount(ctx context.Context, email strin
|
||||
|
||||
err := r.db.
|
||||
Table("users").
|
||||
Select("users.*, user_roles.role_id, user_roles.partner_id, roles.role_name, partners.name as partner_name").
|
||||
Select("users.*, user_roles.role_id, user_roles.partner_id, roles.role_name, partners.name as partner_name, partners.status as partner_status").
|
||||
Where("users.email = ?", email).
|
||||
Joins("left join user_roles on users.id = user_roles.user_id").
|
||||
Joins("left join roles on user_roles.role_id = roles.role_id").
|
||||
Joins("left join partners on user_roles.partner_id = partners.id").
|
||||
First(&user).Error
|
||||
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("user with email %s does not exist", email) // or use a custom error type
|
||||
|
||||
@ -44,9 +44,9 @@ func (c *CryptoImpl) ValidateWT(tokenString string) (*jwt.Token, error) {
|
||||
}
|
||||
|
||||
func (c *CryptoImpl) GenerateJWT(user *entity.User) (string, error) {
|
||||
branchID := int64(0)
|
||||
partnerID := int64(0)
|
||||
if user.PartnerID != nil {
|
||||
branchID = *user.PartnerID
|
||||
partnerID = *user.PartnerID
|
||||
}
|
||||
|
||||
claims := &entity.JWTAuthClaims{
|
||||
@ -60,7 +60,7 @@ func (c *CryptoImpl) GenerateJWT(user *entity.User) (string, error) {
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
Role: int(user.RoleID),
|
||||
BranchID: branchID,
|
||||
PartnerID: partnerID,
|
||||
}
|
||||
|
||||
token, err := jwt.
|
||||
|
||||
@ -28,6 +28,15 @@ func (b *PartnerRepository) Create(ctx context.Context, Partner *entity.PartnerD
|
||||
return Partner, nil
|
||||
}
|
||||
|
||||
func (b *PartnerRepository) CreateWithTx(ctx context.Context, tx *gorm.DB, Partner *entity.PartnerDB) (*entity.PartnerDB, error) {
|
||||
err := tx.Create(Partner).Error
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when create Partner", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return Partner, nil
|
||||
}
|
||||
|
||||
func (b *PartnerRepository) Update(ctx context.Context, Partner *entity.PartnerDB) (*entity.PartnerDB, error) {
|
||||
if err := b.db.Save(Partner).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when update Partner", zap.Error(err))
|
||||
|
||||
@ -2,14 +2,17 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"furtuna-be/internal/repository/branches"
|
||||
"furtuna-be/internal/repository/orders"
|
||||
"furtuna-be/internal/repository/oss"
|
||||
"furtuna-be/internal/repository/partners"
|
||||
"furtuna-be/internal/repository/products"
|
||||
"furtuna-be/internal/repository/sites"
|
||||
"furtuna-be/internal/repository/studios"
|
||||
"furtuna-be/internal/repository/trx"
|
||||
"furtuna-be/internal/repository/users"
|
||||
|
||||
repository "furtuna-be/internal/repository/wallet"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"gorm.io/gorm"
|
||||
|
||||
@ -31,6 +34,9 @@ type RepoManagerImpl struct {
|
||||
Order Order
|
||||
OSS OSSRepository
|
||||
Partner PartnerRepository
|
||||
Site SiteRepository
|
||||
Trx TransactionManager
|
||||
Wallet WalletRepository
|
||||
}
|
||||
|
||||
func NewRepoManagerImpl(db *gorm.DB, cfg *config.Config) *RepoManagerImpl {
|
||||
@ -45,6 +51,9 @@ func NewRepoManagerImpl(db *gorm.DB, cfg *config.Config) *RepoManagerImpl {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +78,7 @@ type Crypto interface {
|
||||
|
||||
type User interface {
|
||||
Create(ctx context.Context, user *entity.UserDB) (*entity.UserDB, error)
|
||||
CreateWithTx(ctx context.Context, tx *gorm.DB, user *entity.UserDB) (*entity.UserDB, error)
|
||||
GetAllUsers(ctx context.Context, req entity.UserSearch) (entity.UserList, int, error)
|
||||
GetUserByID(ctx context.Context, id int64) (*entity.UserDB, error)
|
||||
GetUserByEmail(ctx context.Context, email string) (*entity.UserDB, error)
|
||||
@ -115,8 +125,28 @@ type OSSRepository interface {
|
||||
|
||||
type PartnerRepository interface {
|
||||
Create(ctx context.Context, branch *entity.PartnerDB) (*entity.PartnerDB, error)
|
||||
CreateWithTx(ctx context.Context, tx *gorm.DB, Partner *entity.PartnerDB) (*entity.PartnerDB, error)
|
||||
Update(ctx context.Context, branch *entity.PartnerDB) (*entity.PartnerDB, error)
|
||||
GetByID(ctx context.Context, id int64) (*entity.PartnerDB, error)
|
||||
GetAll(ctx context.Context, req entity.PartnerSearch) (entity.PartnerList, int, error)
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
type SiteRepository interface {
|
||||
Upsert(ctx context.Context, site *entity.Site) (*entity.Site, error)
|
||||
Create(ctx context.Context, branch *entity.SiteDB) (*entity.SiteDB, error)
|
||||
Update(ctx context.Context, branch *entity.SiteDB) (*entity.SiteDB, error)
|
||||
GetByID(ctx context.Context, id int64) (*entity.SiteDB, error)
|
||||
GetAll(ctx context.Context, req entity.SiteSearch) (entity.SiteList, int, error)
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
type TransactionManager interface {
|
||||
Begin(ctx context.Context, opts ...*sql.TxOptions) (*gorm.DB, error)
|
||||
Commit(session *gorm.DB) *gorm.DB
|
||||
Rollback(session *gorm.DB) *gorm.DB
|
||||
}
|
||||
|
||||
type WalletRepository interface {
|
||||
Create(ctx context.Context, tx *gorm.DB, wallet *entity.Wallet) (*entity.Wallet, error)
|
||||
}
|
||||
|
||||
131
internal/repository/sites/sites.go
Normal file
131
internal/repository/sites/sites.go
Normal file
@ -0,0 +1,131 @@
|
||||
package sites
|
||||
|
||||
import (
|
||||
"context"
|
||||
"furtuna-be/internal/common/logger"
|
||||
"furtuna-be/internal/entity"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type SiteRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewSiteRepository(db *gorm.DB) *SiteRepository {
|
||||
return &SiteRepository{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SiteRepository) Upsert(ctx context.Context, site *entity.Site) (*entity.Site, error) {
|
||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||
if site.ID != 0 {
|
||||
// Update site
|
||||
if err := tx.Save(site).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Create new site
|
||||
if err := tx.Create(site).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(site.Products) > 0 {
|
||||
for i := range site.Products {
|
||||
site.Products[i].SiteID = site.ID
|
||||
if site.Products[i].ID != 0 {
|
||||
// Update existing product
|
||||
if err := tx.Save(&site.Products[i]).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Create new product
|
||||
if err := tx.Create(&site.Products[i]).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when upserting site", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return site, nil
|
||||
}
|
||||
|
||||
func (r *SiteRepository) Create(ctx context.Context, site *entity.SiteDB) (*entity.SiteDB, error) {
|
||||
err := r.db.Create(site).Error
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when creating site", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return site, nil
|
||||
}
|
||||
|
||||
func (r *SiteRepository) Update(ctx context.Context, site *entity.SiteDB) (*entity.SiteDB, error) {
|
||||
if err := r.db.Save(site).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when updating site", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return site, nil
|
||||
}
|
||||
|
||||
func (r *SiteRepository) GetByID(ctx context.Context, id int64) (*entity.SiteDB, error) {
|
||||
site := new(entity.SiteDB)
|
||||
if err := r.db.First(site, id).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when getting site by ID", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return site, nil
|
||||
}
|
||||
|
||||
func (r *SiteRepository) GetAll(ctx context.Context, req entity.SiteSearch) (entity.SiteList, int, error) {
|
||||
var sites []*entity.SiteDB
|
||||
var total int64
|
||||
|
||||
query := r.db
|
||||
query = query.Where("deleted_at IS NULL")
|
||||
|
||||
if req.Search != "" {
|
||||
query = query.Where("name ILIKE ?", "%"+req.Search+"%")
|
||||
}
|
||||
|
||||
if req.Name != "" {
|
||||
query = query.Where("name ILIKE ?", "%"+req.Name+"%")
|
||||
}
|
||||
|
||||
if req.Limit > 0 {
|
||||
query = query.Limit(req.Limit)
|
||||
}
|
||||
|
||||
if req.Offset > 0 {
|
||||
query = query.Offset(req.Offset)
|
||||
}
|
||||
|
||||
if err := query.Find(&sites).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when getting all sites", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := r.db.Model(&entity.SiteDB{}).Where(query).Count(&total).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when counting sites", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return sites, int(total), nil
|
||||
}
|
||||
|
||||
func (r *SiteRepository) Delete(ctx context.Context, id int64) error {
|
||||
site := new(entity.SiteDB)
|
||||
site.ID = id
|
||||
if err := r.db.Delete(site).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
33
internal/repository/trx/trx.go
Normal file
33
internal/repository/trx/trx.go
Normal file
@ -0,0 +1,33 @@
|
||||
package trx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GormTransactionManager struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewGormTransactionManager(db *gorm.DB) *GormTransactionManager {
|
||||
return &GormTransactionManager{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (tm *GormTransactionManager) Begin(ctx context.Context, opts ...*sql.TxOptions) (*gorm.DB, error) {
|
||||
tx := tm.db.Begin(opts...)
|
||||
if tx.Error != nil {
|
||||
return nil, tx.Error
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
func (tm *GormTransactionManager) Commit(tx *gorm.DB) *gorm.DB {
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (tm *GormTransactionManager) Rollback(tx *gorm.DB) *gorm.DB {
|
||||
return tx.Rollback()
|
||||
}
|
||||
@ -51,6 +51,29 @@ func (r *UserRepository) Create(ctx context.Context, user *entity.UserDB) (*enti
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (r *UserRepository) CreateWithTx(ctx context.Context, tx *gorm.DB, user *entity.UserDB) (*entity.UserDB, error) {
|
||||
user.ID = 0
|
||||
if err := tx.Select("name", "email", "password", "status", "created_by", "nik", "user_type", "phone_number").Create(user).Error; err != nil {
|
||||
logError(ctx, "creating user", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := tx.First(user, user.ID).Error; err != nil {
|
||||
tx.Rollback()
|
||||
logError(ctx, "retrieving user", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userRole := user.ToUserRoleDB()
|
||||
if err := tx.Create(userRole).Error; err != nil {
|
||||
tx.Rollback()
|
||||
logError(ctx, "creating user role", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (b *UserRepository) GetAllUsers(ctx context.Context, req entity.UserSearch) (entity.UserList, int, error) {
|
||||
var users []*entity.UserDB
|
||||
var total int64
|
||||
|
||||
65
internal/repository/wallet/wallet.go
Normal file
65
internal/repository/wallet/wallet.go
Normal file
@ -0,0 +1,65 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"furtuna-be/internal/common/logger"
|
||||
"furtuna-be/internal/entity"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type WalletRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewWalletRepository(db *gorm.DB) *WalletRepository {
|
||||
return &WalletRepository{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *WalletRepository) Create(ctx context.Context, tx *gorm.DB, wallet *entity.Wallet) (*entity.Wallet, error) {
|
||||
err := tx.Create(wallet).Error
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when creating wallet", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return wallet, nil
|
||||
}
|
||||
|
||||
func (r *WalletRepository) Update(ctx context.Context, wallet *entity.Wallet) (*entity.Wallet, error) {
|
||||
if err := r.db.Save(wallet).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when updating wallet", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return wallet, nil
|
||||
}
|
||||
|
||||
func (r *WalletRepository) GetByID(ctx context.Context, id int64) (*entity.Wallet, error) {
|
||||
wallet := new(entity.Wallet)
|
||||
if err := r.db.First(wallet, id).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when getting wallet by id", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return wallet, nil
|
||||
}
|
||||
|
||||
func (r *WalletRepository) GetAll(ctx context.Context) ([]*entity.Wallet, error) {
|
||||
var wallets []*entity.Wallet
|
||||
if err := r.db.Find(&wallets).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when getting all wallets", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return wallets, nil
|
||||
}
|
||||
|
||||
func (r *WalletRepository) Delete(ctx context.Context, id int64) error {
|
||||
wallet := new(entity.Wallet)
|
||||
wallet.ID = id
|
||||
if err := r.db.Delete(wallet).Error; err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when deleting wallet", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"furtuna-be/internal/handlers/http/oss"
|
||||
"furtuna-be/internal/handlers/http/partner"
|
||||
"furtuna-be/internal/handlers/http/product"
|
||||
site "furtuna-be/internal/handlers/http/sites"
|
||||
"furtuna-be/internal/handlers/http/studio"
|
||||
"furtuna-be/internal/handlers/http/user"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
@ -52,6 +53,7 @@ func RegisterPrivateRoutes(app *app.Server, serviceManager *services.ServiceMana
|
||||
order.NewHandler(serviceManager.OrderSvc),
|
||||
oss.NewOssHandler(serviceManager.OSSSvc),
|
||||
partner.NewHandler(serviceManager.PartnerSvc),
|
||||
site.NewHandler(serviceManager.SiteSvc),
|
||||
}
|
||||
|
||||
for _, handler := range serverRoutes {
|
||||
|
||||
@ -6,31 +6,68 @@ import (
|
||||
"furtuna-be/internal/common/mycontext"
|
||||
"furtuna-be/internal/entity"
|
||||
"furtuna-be/internal/repository"
|
||||
|
||||
"furtuna-be/internal/services/users"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type PartnerService struct {
|
||||
repo repository.PartnerRepository
|
||||
trx repository.TransactionManager
|
||||
userSvc *users.UserService
|
||||
walletRepo repository.WalletRepository
|
||||
}
|
||||
|
||||
func NewPartnerService(repo repository.PartnerRepository) *PartnerService {
|
||||
func NewPartnerService(repo repository.PartnerRepository,
|
||||
userSvc *users.UserService, repoManager repository.TransactionManager,
|
||||
walletRepo repository.WalletRepository) *PartnerService {
|
||||
return &PartnerService{
|
||||
repo: repo,
|
||||
userSvc: userSvc,
|
||||
trx: repoManager,
|
||||
walletRepo: walletRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PartnerService) Create(ctx mycontext.Context, PartnerReq *entity.Partner) (*entity.Partner, error) {
|
||||
PartnerDB := PartnerReq.ToPartnerDB()
|
||||
PartnerDB.CreatedBy = ctx.RequestedBy()
|
||||
func (s *PartnerService) Create(ctx mycontext.Context, partnerReq *entity.CreatePartnerRequest) (*entity.Partner, error) {
|
||||
var err error
|
||||
|
||||
PartnerDB, err := s.repo.Create(ctx, PartnerDB)
|
||||
tx, err := s.trx.Begin(ctx)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when create Partner", zap.Error(err))
|
||||
logger.ContextLogger(ctx).Error("error when starting transaction", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return PartnerDB.ToPartner(), nil
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
s.trx.Rollback(tx)
|
||||
panic(r)
|
||||
} else if err != nil {
|
||||
s.trx.Rollback(tx)
|
||||
} else {
|
||||
err = s.trx.Commit(tx).Error
|
||||
}
|
||||
}()
|
||||
|
||||
// Create Partner
|
||||
partnerDB := partnerReq.ToPartnerDB(ctx.RequestedBy())
|
||||
if partnerDB, err = s.repo.CreateWithTx(ctx, tx, partnerDB); err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when creating partner", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
adminUser := partnerReq.ToUserAdmin(partnerDB.ID)
|
||||
if adminUser, err = s.userSvc.CreateWithTx(ctx, tx, adminUser); err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when creating admin user", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
partnerWallet := partnerReq.ToWallet(partnerDB.ID)
|
||||
if partnerWallet, err = s.walletRepo.Create(ctx, tx, partnerWallet); err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when creating wallet", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return partnerDB.ToPartner(), nil
|
||||
}
|
||||
|
||||
func (s *PartnerService) Update(ctx mycontext.Context, id int64, PartnerReq *entity.Partner) (*entity.Partner, error) {
|
||||
|
||||
@ -8,8 +8,10 @@ import (
|
||||
"furtuna-be/internal/services/oss"
|
||||
"furtuna-be/internal/services/partner"
|
||||
"furtuna-be/internal/services/product"
|
||||
"furtuna-be/internal/services/sites"
|
||||
"furtuna-be/internal/services/studio"
|
||||
"furtuna-be/internal/services/users"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"furtuna-be/config"
|
||||
"furtuna-be/internal/entity"
|
||||
@ -28,6 +30,7 @@ type ServiceManagerImpl struct {
|
||||
OrderSvc Order
|
||||
OSSSvc OSSService
|
||||
PartnerSvc Partner
|
||||
SiteSvc Site
|
||||
}
|
||||
|
||||
func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) *ServiceManagerImpl {
|
||||
@ -40,7 +43,9 @@ func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl)
|
||||
ProductSvc: product.NewProductService(repo.Product),
|
||||
OrderSvc: order.NewOrderService(repo.Order, repo.Product, repo.Studio),
|
||||
OSSSvc: oss.NewOSSService(repo.OSS),
|
||||
PartnerSvc: partner.NewPartnerService(repo.Partner),
|
||||
PartnerSvc: partner.NewPartnerService(
|
||||
repo.Partner, users.NewUserService(repo.User, repo.Branch), repo.Trx, repo.Wallet),
|
||||
SiteSvc: site.NewSiteService(repo.Site),
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,6 +63,7 @@ type Event interface {
|
||||
|
||||
type User interface {
|
||||
Create(ctx mycontext.Context, userReq *entity.User) (*entity.User, error)
|
||||
CreateWithTx(ctx mycontext.Context, tx *gorm.DB, userReq *entity.User) (*entity.User, error)
|
||||
GetAll(ctx mycontext.Context, search entity.UserSearch) ([]*entity.User, int, error)
|
||||
Update(ctx mycontext.Context, id int64, userReq *entity.User) (*entity.User, error)
|
||||
GetByID(ctx mycontext.Context, id int64) (*entity.User, error)
|
||||
@ -102,9 +108,17 @@ type OSSService interface {
|
||||
}
|
||||
|
||||
type Partner interface {
|
||||
Create(ctx mycontext.Context, branchReq *entity.Partner) (*entity.Partner, error)
|
||||
Create(ctx mycontext.Context, branchReq *entity.CreatePartnerRequest) (*entity.Partner, error)
|
||||
Update(ctx mycontext.Context, id int64, branchReq *entity.Partner) (*entity.Partner, error)
|
||||
GetByID(ctx context.Context, id int64) (*entity.Partner, error)
|
||||
GetAll(ctx context.Context, search entity.PartnerSearch) ([]*entity.Partner, int, error)
|
||||
Delete(ctx mycontext.Context, id int64) error
|
||||
}
|
||||
|
||||
type Site interface {
|
||||
Create(ctx mycontext.Context, branchReq *entity.Site) (*entity.Site, error)
|
||||
Update(ctx mycontext.Context, id int64, branchReq *entity.Site) (*entity.Site, error)
|
||||
GetByID(ctx context.Context, id int64) (*entity.Site, error)
|
||||
GetAll(ctx context.Context, search entity.SiteSearch) ([]*entity.Site, int, error)
|
||||
Delete(ctx mycontext.Context, id int64) error
|
||||
}
|
||||
|
||||
89
internal/services/sites/sites.go
Normal file
89
internal/services/sites/sites.go
Normal file
@ -0,0 +1,89 @@
|
||||
package site
|
||||
|
||||
import (
|
||||
"context"
|
||||
"furtuna-be/internal/common/logger"
|
||||
"furtuna-be/internal/common/mycontext"
|
||||
"furtuna-be/internal/entity"
|
||||
"furtuna-be/internal/repository"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type SiteService struct {
|
||||
repo repository.SiteRepository
|
||||
}
|
||||
|
||||
func NewSiteService(repo repository.SiteRepository) *SiteService {
|
||||
return &SiteService{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SiteService) Create(ctx mycontext.Context, siteReq *entity.Site) (*entity.Site, error) {
|
||||
siteDB := siteReq
|
||||
siteDB.CreatedBy = ctx.RequestedBy()
|
||||
|
||||
siteDB, err := s.repo.Upsert(ctx, siteDB)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when creating site", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return siteDB, nil
|
||||
}
|
||||
|
||||
func (s *SiteService) Update(ctx mycontext.Context, id int64, siteReq *entity.Site) (*entity.Site, error) {
|
||||
existingSite, err := s.repo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingSite.ToUpdatedSite(ctx.RequestedBy(), *siteReq)
|
||||
|
||||
updatedSiteDB, err := s.repo.Update(ctx, existingSite.ToSiteDB())
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when updating site", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return updatedSiteDB.ToSite(), nil
|
||||
}
|
||||
|
||||
func (s *SiteService) GetByID(ctx context.Context, id int64) (*entity.Site, error) {
|
||||
siteDB, err := s.repo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when getting site by ID", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return siteDB.ToSite(), nil
|
||||
}
|
||||
|
||||
func (s *SiteService) GetAll(ctx context.Context, search entity.SiteSearch) ([]*entity.Site, int, error) {
|
||||
sites, total, err := s.repo.GetAll(ctx, search)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when getting all sites", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return sites.ToSiteList(), total, nil
|
||||
}
|
||||
|
||||
func (s *SiteService) Delete(ctx mycontext.Context, id int64) error {
|
||||
siteDB, err := s.repo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when getting site by ID", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
siteDB.SetDeleted(ctx.RequestedBy())
|
||||
|
||||
_, err = s.repo.Update(ctx, siteDB)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when updating site", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -3,6 +3,7 @@ package users
|
||||
import (
|
||||
"fmt"
|
||||
"furtuna-be/internal/common/mycontext"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
@ -48,6 +49,31 @@ func (s *UserService) Create(ctx mycontext.Context, userReq *entity.User) (*enti
|
||||
return userDB.ToUser(), nil
|
||||
}
|
||||
|
||||
func (s *UserService) CreateWithTx(ctx mycontext.Context, tx *gorm.DB, userReq *entity.User) (*entity.User, error) {
|
||||
//check
|
||||
userExist, err := s.repo.GetUserByEmail(ctx, userReq.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userExist != nil {
|
||||
return nil, fmt.Errorf("Email already exist")
|
||||
}
|
||||
|
||||
userDB, err := userReq.ToUserDB(ctx.RequestedBy())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userDB, err = s.repo.CreateWithTx(ctx, tx, userDB)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when create user", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return userDB.ToUser(), nil
|
||||
}
|
||||
|
||||
func (s *UserService) GetAll(ctx mycontext.Context, search entity.UserSearch) ([]*entity.User, int, error) {
|
||||
|
||||
users, total, err := s.repo.GetAllUsers(ctx, search)
|
||||
@ -82,7 +108,7 @@ func (s *UserService) Update(ctx mycontext.Context, id int64, userReq *entity.Us
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingUser.BranchName = branch.Name
|
||||
existingUser.PartnerName = branch.Name
|
||||
}
|
||||
|
||||
err = existingUser.ToUpdatedUser(*userReq)
|
||||
|
||||
@ -3,4 +3,9 @@ CREATE TABLE roles (
|
||||
role_name VARCHAR(255) NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO roles(role_id, role_name) VALUES (1, 'super_admin'), (2, 'branch_admin');
|
||||
INSERT INTO roles(role_id, role_name)
|
||||
VALUES (1, 'super_admin'),
|
||||
(2, 'admin'),
|
||||
(3, 'admin_partner'),
|
||||
(4, 'admin_site'),
|
||||
(5, 'cashier');
|
||||
|
||||
@ -2,11 +2,15 @@ CREATE TABLE partners
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
status varchar,
|
||||
Address varchar,
|
||||
status VARCHAR(50),
|
||||
license_expired_date DATE,
|
||||
address VARCHAR(255),
|
||||
bank_name VARCHAR(255),
|
||||
bank_account_number VARCHAR(50),
|
||||
bank_account_holder_name VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by INTEGER,
|
||||
updated_by INTEGER,
|
||||
deleted_at timestamp
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
@ -1,10 +1,13 @@
|
||||
CREATE TABLE products
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
partner_id INTEGER,
|
||||
site_id INTEGER,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
type VARCHAR,
|
||||
prices INTEGER[],
|
||||
price decimal,
|
||||
is_weekend_ticket boolean,
|
||||
is_season_ticket boolean,
|
||||
status VARCHAR,
|
||||
description VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
|
||||
0
migrations/000009_add_wallet.down.sql
Normal file
0
migrations/000009_add_wallet.down.sql
Normal file
11
migrations/000009_add_wallet.up.sql
Normal file
11
migrations/000009_add_wallet.up.sql
Normal file
@ -0,0 +1,11 @@
|
||||
CREATE TABLE public.wallets
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
partner_id INTEGER NOT NULL,
|
||||
balance DECIMAL(18, 2) NOT NULL DEFAULT 0.00,
|
||||
currency VARCHAR(3) NOT NULL,
|
||||
status VARCHAR(50),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
FOREIGN KEY (partner_id) REFERENCES partners (id) ON DELETE CASCADE
|
||||
);
|
||||
Loading…
x
Reference in New Issue
Block a user