mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Revert "Merge branch 'fix/implement-fifo-v2' into 'dev/fifo-v2'"
This reverts merge request !340
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto"
|
||||
uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
|
||||
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
)
|
||||
|
||||
// === DTO Structs ===
|
||||
@@ -18,9 +17,6 @@ type ProductRelationDTO struct {
|
||||
ProductPrice float64 `gorm:"type:numeric(15,3);not null"`
|
||||
SellingPrice *float64 `gorm:"type:numeric(15,3)"`
|
||||
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
||||
Flag *string `json:"flag,omitempty"`
|
||||
SubFlag *string `json:"sub_flag,omitempty"`
|
||||
SubFlags *[]string `json:"sub_flags,omitempty"`
|
||||
Flags *[]string `json:"flags,omitempty"`
|
||||
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
||||
Suppliers []ProductSupplierDTO `json:"suppliers"`
|
||||
@@ -35,9 +31,6 @@ type ProductListDTO struct {
|
||||
SellingPrice *float64 `json:"selling_price,omitempty"`
|
||||
Tax *float64 `json:"tax,omitempty"`
|
||||
ExpiryPeriod *int `json:"expiry_period,omitempty"`
|
||||
Flag *string `json:"flag,omitempty"`
|
||||
SubFlag *string `json:"sub_flag,omitempty"`
|
||||
SubFlags []string `json:"sub_flags,omitempty"`
|
||||
Flags []string `json:"flags"`
|
||||
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
||||
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
||||
@@ -66,13 +59,6 @@ func ToProductRelationDTO(e entity.Product) ProductRelationDTO {
|
||||
for i, f := range e.Flags {
|
||||
flags[i] = f.Name
|
||||
}
|
||||
flag, subFlag, subFlags := resolveProductFlagAndSubFlags(flags)
|
||||
var subFlagsRef *[]string
|
||||
if len(subFlags) > 0 {
|
||||
values := make([]string, len(subFlags))
|
||||
copy(values, subFlags)
|
||||
subFlagsRef = &values
|
||||
}
|
||||
|
||||
var uomRef *uomDTO.UomRelationDTO
|
||||
if e.Uom.Id != 0 {
|
||||
@@ -91,9 +77,6 @@ func ToProductRelationDTO(e entity.Product) ProductRelationDTO {
|
||||
Name: e.Name,
|
||||
ProductPrice: e.ProductPrice,
|
||||
SellingPrice: e.SellingPrice,
|
||||
Flag: flag,
|
||||
SubFlag: subFlag,
|
||||
SubFlags: subFlagsRef,
|
||||
Flags: &flags,
|
||||
Uom: uomRef,
|
||||
ProductCategory: categoryRef,
|
||||
@@ -118,7 +101,6 @@ func ToProductListDTO(e entity.Product) ProductListDTO {
|
||||
for i, f := range e.Flags {
|
||||
flags[i] = f.Name
|
||||
}
|
||||
flag, subFlag, subFlags := resolveProductFlagAndSubFlags(flags)
|
||||
|
||||
var uomRef *uomDTO.UomRelationDTO
|
||||
if e.Uom.Id != 0 {
|
||||
@@ -129,9 +111,6 @@ func ToProductListDTO(e entity.Product) ProductListDTO {
|
||||
return ProductListDTO{
|
||||
Id: e.Id,
|
||||
Name: e.Name,
|
||||
Flag: flag,
|
||||
SubFlag: subFlag,
|
||||
SubFlags: subFlags,
|
||||
Flags: flags,
|
||||
Uom: uomRef,
|
||||
Brand: e.Brand,
|
||||
@@ -162,58 +141,6 @@ func ToProductDetailDTO(e entity.Product) ProductDetailDTO {
|
||||
}
|
||||
}
|
||||
|
||||
func resolveProductFlagAndSubFlags(flags []string) (*string, *string, []string) {
|
||||
normalized := utils.NormalizeFlagTypes(flags)
|
||||
if len(normalized) == 0 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
available := make(map[utils.FlagType]struct{}, len(normalized))
|
||||
for _, flag := range normalized {
|
||||
available[flag] = struct{}{}
|
||||
}
|
||||
|
||||
var selectedFlag utils.FlagType
|
||||
for _, mainFlag := range utils.ProductMainFlags() {
|
||||
if _, ok := available[mainFlag]; ok {
|
||||
selectedFlag = mainFlag
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if selectedFlag == "" {
|
||||
subToMain := utils.ProductSubFlagToFlag()
|
||||
for _, flag := range normalized {
|
||||
if parent, ok := subToMain[flag]; ok {
|
||||
selectedFlag = parent
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if selectedFlag == "" {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
flag := string(selectedFlag)
|
||||
|
||||
var subFlag *string
|
||||
subFlagValues := make([]string, 0)
|
||||
subFlagsByMain := utils.ProductSubFlagsByFlag()
|
||||
for _, sub := range subFlagsByMain[selectedFlag] {
|
||||
if _, ok := available[sub]; ok {
|
||||
subFlagValues = append(subFlagValues, string(sub))
|
||||
}
|
||||
}
|
||||
|
||||
if len(subFlagValues) > 0 {
|
||||
first := subFlagValues[0]
|
||||
subFlag = &first
|
||||
}
|
||||
|
||||
return &flag, subFlag, subFlagValues
|
||||
}
|
||||
|
||||
func toProductSupplierDTOs(relations []entity.ProductSupplier) []ProductSupplierDTO {
|
||||
if len(relations) == 0 {
|
||||
return make([]ProductSupplierDTO, 0)
|
||||
|
||||
@@ -41,151 +41,6 @@ func normalizeProductFlags(raw []string) ([]string, error) {
|
||||
return utils.FlagTypesToStrings(normalized), nil
|
||||
}
|
||||
|
||||
func productMainFlagOptionsString() []string {
|
||||
mainFlags := utils.ProductMainFlags()
|
||||
result := make([]string, len(mainFlags))
|
||||
for i, flag := range mainFlags {
|
||||
result[i] = string(flag)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func productSubFlagOptionsString(flag utils.FlagType) []string {
|
||||
subFlagsByFlag := utils.ProductSubFlagsByFlag()
|
||||
subFlags := subFlagsByFlag[flag]
|
||||
result := make([]string, len(subFlags))
|
||||
for i, subFlag := range subFlags {
|
||||
result[i] = string(subFlag)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func normalizeStructuredSubFlagsInput(subFlagRaw *string, subFlagsRaw []string, hasSubFlagsField bool) ([]utils.FlagType, error) {
|
||||
values := make([]string, 0, len(subFlagsRaw)+1)
|
||||
|
||||
if subFlagRaw != nil {
|
||||
single := strings.TrimSpace(*subFlagRaw)
|
||||
if single == "" {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "sub_flag cannot be empty")
|
||||
}
|
||||
values = append(values, single)
|
||||
}
|
||||
|
||||
if hasSubFlagsField {
|
||||
for _, raw := range subFlagsRaw {
|
||||
item := strings.TrimSpace(raw)
|
||||
if item == "" {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "sub_flags cannot contain empty value")
|
||||
}
|
||||
values = append(values, item)
|
||||
}
|
||||
}
|
||||
|
||||
if len(values) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return utils.NormalizeFlagTypes(values), nil
|
||||
}
|
||||
|
||||
func resolveProductFlagsFromFlagInput(flagRaw *string, subFlagRaw *string, subFlagsRaw []string, hasSubFlagsField bool) ([]string, bool, error) {
|
||||
if flagRaw == nil && subFlagRaw == nil && !hasSubFlagsField {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
if flagRaw == nil && (subFlagRaw != nil || hasSubFlagsField) {
|
||||
return nil, false, fiber.NewError(fiber.StatusBadRequest, "flag is required when sub_flag/sub_flags is provided")
|
||||
}
|
||||
|
||||
flagText := strings.TrimSpace(*flagRaw)
|
||||
if flagText == "" {
|
||||
return nil, false, fiber.NewError(fiber.StatusBadRequest, "flag cannot be empty")
|
||||
}
|
||||
|
||||
flag := utils.CanonicalFlagType(flagText)
|
||||
if !utils.IsProductMainFlag(flag) {
|
||||
return nil, false, fiber.NewError(
|
||||
fiber.StatusBadRequest,
|
||||
fmt.Sprintf("Invalid product flag: %s. Allowed flags: %s", flagText, strings.Join(productMainFlagOptionsString(), ", ")),
|
||||
)
|
||||
}
|
||||
|
||||
out := []string{string(flag)}
|
||||
|
||||
normalizedSubFlags, err := normalizeStructuredSubFlagsInput(subFlagRaw, subFlagsRaw, hasSubFlagsField)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
if len(normalizedSubFlags) == 0 {
|
||||
if !utils.ProductFlagAllowWithoutSubFlag(flag) {
|
||||
return nil, false, fiber.NewError(
|
||||
fiber.StatusBadRequest,
|
||||
fmt.Sprintf("sub_flag/sub_flags is required for flag %s", string(flag)),
|
||||
)
|
||||
}
|
||||
return out, true, nil
|
||||
}
|
||||
|
||||
invalidSubFlags := make([]string, 0)
|
||||
for _, subFlag := range normalizedSubFlags {
|
||||
if !utils.IsValidProductSubFlag(flag, subFlag) {
|
||||
invalidSubFlags = append(invalidSubFlags, string(subFlag))
|
||||
}
|
||||
}
|
||||
if len(invalidSubFlags) > 0 {
|
||||
return nil, false, fiber.NewError(
|
||||
fiber.StatusBadRequest,
|
||||
fmt.Sprintf("Invalid sub_flags %s for flag %s. Allowed sub_flags: %s", strings.Join(invalidSubFlags, ", "), string(flag), strings.Join(productSubFlagOptionsString(flag), ", ")),
|
||||
)
|
||||
}
|
||||
|
||||
out = append(out, utils.FlagTypesToStrings(normalizedSubFlags)...)
|
||||
return out, true, nil
|
||||
}
|
||||
|
||||
func resolveCreateProductFlags(req *validation.Create) ([]string, error) {
|
||||
hasStructuredInput := req.Flag != nil || req.SubFlag != nil || req.SubFlags != nil
|
||||
if len(req.Flags) > 0 && hasStructuredInput {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Use either flags or flag/sub_flag/sub_flags, not both")
|
||||
}
|
||||
|
||||
if len(req.Flags) > 0 {
|
||||
return normalizeProductFlags(req.Flags)
|
||||
}
|
||||
|
||||
flags, _, err := resolveProductFlagsFromFlagInput(req.Flag, req.SubFlag, req.SubFlags, req.SubFlags != nil)
|
||||
return flags, err
|
||||
}
|
||||
|
||||
func resolveUpdateProductFlags(req *validation.Update) (bool, []string, error) {
|
||||
hasStructuredInput := req.Flag != nil || req.SubFlag != nil || req.SubFlags != nil
|
||||
|
||||
if req.Flags != nil {
|
||||
if hasStructuredInput {
|
||||
if len(*req.Flags) > 0 {
|
||||
return false, nil, fiber.NewError(fiber.StatusBadRequest, "Use either flags or flag/sub_flag/sub_flags, not both")
|
||||
}
|
||||
} else {
|
||||
flags, err := normalizeProductFlags(*req.Flags)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, flags, nil
|
||||
}
|
||||
}
|
||||
|
||||
subFlagsRaw := make([]string, 0)
|
||||
if req.SubFlags != nil {
|
||||
subFlagsRaw = *req.SubFlags
|
||||
}
|
||||
flags, provided, err := resolveProductFlagsFromFlagInput(req.Flag, req.SubFlag, subFlagsRaw, req.SubFlags != nil)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return provided, flags, nil
|
||||
}
|
||||
|
||||
func NewProductService(repo repository.ProductRepository, validate *validator.Validate) ProductService {
|
||||
return &productService{
|
||||
Log: utils.Log,
|
||||
@@ -322,7 +177,7 @@ func (s *productService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
||||
}
|
||||
}
|
||||
|
||||
productFlags, flagErr := resolveCreateProductFlags(req)
|
||||
productFlags, flagErr := normalizeProductFlags(req.Flags)
|
||||
if flagErr != nil {
|
||||
return nil, flagErr
|
||||
}
|
||||
@@ -482,10 +337,13 @@ func (s productService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
flagUpdate bool
|
||||
flagValues []string
|
||||
)
|
||||
var flagErr error
|
||||
flagUpdate, flagValues, flagErr = resolveUpdateProductFlags(req)
|
||||
if flagErr != nil {
|
||||
return nil, flagErr
|
||||
if req.Flags != nil {
|
||||
flagUpdate = true
|
||||
var flagErr error
|
||||
flagValues, flagErr = normalizeProductFlags(*req.Flags)
|
||||
if flagErr != nil {
|
||||
return nil, flagErr
|
||||
}
|
||||
}
|
||||
|
||||
if len(updateBody) == 0 && !supplierUpdate && !flagUpdate {
|
||||
|
||||
@@ -6,37 +6,31 @@ type SupplierPrice struct {
|
||||
}
|
||||
|
||||
type Create struct {
|
||||
Name string `json:"name" validate:"required_strict,min=3,max=50"`
|
||||
Brand string `json:"brand" validate:"required_strict,min=2,max=50"`
|
||||
Sku *string `json:"sku,omitempty" validate:"omitempty,max=100"`
|
||||
UomID uint `json:"uom_id" validate:"required,gt=0"`
|
||||
ProductCategoryID uint `json:"product_category_id" validate:"required,gt=0"`
|
||||
ProductPrice float64 `json:"product_price" validate:"required"`
|
||||
SellingPrice *float64 `json:"selling_price,omitempty" validate:"omitempty"`
|
||||
Tax *float64 `json:"tax,omitempty" validate:"omitempty"`
|
||||
ExpiryPeriod *int `json:"expiry_period,omitempty" validate:"omitempty,gt=0"`
|
||||
Name string `json:"name" validate:"required_strict,min=3,max=50"`
|
||||
Brand string `json:"brand" validate:"required_strict,min=2,max=50"`
|
||||
Sku *string `json:"sku,omitempty" validate:"omitempty,max=100"`
|
||||
UomID uint `json:"uom_id" validate:"required,gt=0"`
|
||||
ProductCategoryID uint `json:"product_category_id" validate:"required,gt=0"`
|
||||
ProductPrice float64 `json:"product_price" validate:"required"`
|
||||
SellingPrice *float64 `json:"selling_price,omitempty" validate:"omitempty"`
|
||||
Tax *float64 `json:"tax,omitempty" validate:"omitempty"`
|
||||
ExpiryPeriod *int `json:"expiry_period,omitempty" validate:"omitempty,gt=0"`
|
||||
Suppliers []SupplierPrice `json:"suppliers,omitempty" validate:"omitempty,dive"`
|
||||
Flag *string `json:"flag,omitempty" validate:"omitempty,max=50"`
|
||||
SubFlag *string `json:"sub_flag,omitempty" validate:"omitempty,max=50"`
|
||||
SubFlags []string `json:"sub_flags,omitempty" validate:"omitempty,dive,max=50"`
|
||||
Flags []string `json:"flags,omitempty" validate:"omitempty,dive"`
|
||||
Flags []string `json:"flags,omitempty" validate:"omitempty,dive"`
|
||||
}
|
||||
|
||||
type Update struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=3"`
|
||||
Brand *string `json:"brand,omitempty" validate:"omitempty,min=2"`
|
||||
Sku *string `json:"sku,omitempty" validate:"omitempty"`
|
||||
UomID *uint `json:"uom_id,omitempty" validate:"omitempty,gt=0"`
|
||||
ProductCategoryID *uint `json:"product_category_id,omitempty" validate:"omitempty,gt=0"`
|
||||
ProductPrice *float64 `json:"product_price,omitempty" validate:"omitempty"`
|
||||
SellingPrice *float64 `json:"selling_price,omitempty" validate:"omitempty"`
|
||||
Tax *float64 `json:"tax,omitempty" validate:"omitempty"`
|
||||
ExpiryPeriod *int `json:"expiry_period,omitempty" validate:"omitempty,gt=0"`
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=3"`
|
||||
Brand *string `json:"brand,omitempty" validate:"omitempty,min=2"`
|
||||
Sku *string `json:"sku,omitempty" validate:"omitempty"`
|
||||
UomID *uint `json:"uom_id,omitempty" validate:"omitempty,gt=0"`
|
||||
ProductCategoryID *uint `json:"product_category_id,omitempty" validate:"omitempty,gt=0"`
|
||||
ProductPrice *float64 `json:"product_price,omitempty" validate:"omitempty"`
|
||||
SellingPrice *float64 `json:"selling_price,omitempty" validate:"omitempty"`
|
||||
Tax *float64 `json:"tax,omitempty" validate:"omitempty"`
|
||||
ExpiryPeriod *int `json:"expiry_period,omitempty" validate:"omitempty,gt=0"`
|
||||
Suppliers *[]SupplierPrice `json:"suppliers,omitempty" validate:"omitempty,dive"`
|
||||
Flag *string `json:"flag,omitempty" validate:"omitempty,max=50"`
|
||||
SubFlag *string `json:"sub_flag,omitempty" validate:"omitempty,max=50"`
|
||||
SubFlags *[]string `json:"sub_flags,omitempty" validate:"omitempty,dive,max=50"`
|
||||
Flags *[]string `json:"flags,omitempty" validate:"omitempty,dive"`
|
||||
Flags *[]string `json:"flags,omitempty" validate:"omitempty,dive"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
|
||||
Reference in New Issue
Block a user