mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Merge branch 'dev/fifo-v2' of https://gitlab.com/mbugroup/lti-api into dev/fifo-v2
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
DELETE FROM fifo_stock_v2_flag_members
|
||||||
|
WHERE flag_name = 'AYAM'
|
||||||
|
AND flag_group_code = 'AYAM';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
INSERT INTO fifo_stock_v2_flag_members(flag_name, flag_group_code, priority, is_active, created_at, updated_at)
|
||||||
|
VALUES
|
||||||
|
('AYAM', 'AYAM', 5, TRUE, NOW(), NOW())
|
||||||
|
ON CONFLICT (flag_name) DO UPDATE
|
||||||
|
SET
|
||||||
|
flag_group_code = EXCLUDED.flag_group_code,
|
||||||
|
priority = EXCLUDED.priority,
|
||||||
|
is_active = TRUE,
|
||||||
|
updated_at = NOW();
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -32,6 +32,44 @@ func (r *ConstantRepositoryImpl) GetConstants() (map[string]interface{}, error)
|
|||||||
}
|
}
|
||||||
sort.Strings(flagList)
|
sort.Strings(flagList)
|
||||||
|
|
||||||
|
productMainFlags := utils.ProductMainFlags()
|
||||||
|
productMainFlagValues := make([]string, len(productMainFlags))
|
||||||
|
for i, flag := range productMainFlags {
|
||||||
|
productMainFlagValues[i] = string(flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
type productFlagOption struct {
|
||||||
|
Flag string `json:"flag"`
|
||||||
|
SubFlags []string `json:"sub_flags"`
|
||||||
|
AllowWithoutSubFlag bool `json:"allow_without_sub_flag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
productOptions := utils.ProductFlagOptions()
|
||||||
|
productFlagOptions := make([]productFlagOption, 0, len(productOptions))
|
||||||
|
for _, option := range productOptions {
|
||||||
|
subFlags := make([]string, len(option.SubFlags))
|
||||||
|
for i, subFlag := range option.SubFlags {
|
||||||
|
subFlags[i] = string(subFlag)
|
||||||
|
}
|
||||||
|
productFlagOptions = append(productFlagOptions, productFlagOption{
|
||||||
|
Flag: string(option.Flag),
|
||||||
|
SubFlags: subFlags,
|
||||||
|
AllowWithoutSubFlag: option.AllowWithoutSubFlag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
productSubFlagToFlagRaw := utils.ProductSubFlagToFlag()
|
||||||
|
productSubFlagToFlag := make(map[string]string, len(productSubFlagToFlagRaw))
|
||||||
|
for subFlag, flag := range productSubFlagToFlagRaw {
|
||||||
|
productSubFlagToFlag[string(subFlag)] = string(flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
legacyAliasesRaw := utils.LegacyFlagTypeAliases()
|
||||||
|
legacyAliases := make(map[string]string, len(legacyAliasesRaw))
|
||||||
|
for legacy, canonical := range legacyAliasesRaw {
|
||||||
|
legacyAliases[string(legacy)] = string(canonical)
|
||||||
|
}
|
||||||
|
|
||||||
type approvalStepConstant struct {
|
type approvalStepConstant struct {
|
||||||
StepNumber uint16 `json:"step_number"`
|
StepNumber uint16 `json:"step_number"`
|
||||||
StepName string `json:"step_name"`
|
StepName string `json:"step_name"`
|
||||||
@@ -99,6 +137,12 @@ func (r *ConstantRepositoryImpl) GetConstants() (map[string]interface{}, error)
|
|||||||
"adjustment": map[string]interface{}{
|
"adjustment": map[string]interface{}{
|
||||||
"transaction_subtypes": adjustmentSubtypesByType,
|
"transaction_subtypes": adjustmentSubtypesByType,
|
||||||
},
|
},
|
||||||
|
"legacy_flag_aliases": legacyAliases,
|
||||||
|
"product_flag_mapping": map[string]interface{}{
|
||||||
|
"flags": productMainFlagValues,
|
||||||
|
"options": productFlagOptions,
|
||||||
|
"sub_flag_to_flag": productSubFlagToFlag,
|
||||||
|
},
|
||||||
"approval_workflows": approvalWorkflows,
|
"approval_workflows": approvalWorkflows,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,14 @@ func (u *ProductController) GetAll(c *fiber.Ctx) error {
|
|||||||
ProductCategoryID: c.QueryInt("product_category_id", 0),
|
ProductCategoryID: c.QueryInt("product_category_id", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isDepletionParam := c.Query("is_depletion", ""); isDepletionParam != "" {
|
||||||
|
value, err := strconv.ParseBool(isDepletionParam)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid is_depletion value")
|
||||||
|
}
|
||||||
|
query.IsDepletion = &value
|
||||||
|
}
|
||||||
|
|
||||||
if query.Page < 1 || query.Limit < 1 {
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto"
|
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"
|
uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
|
||||||
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||||
|
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// === DTO Structs ===
|
// === DTO Structs ===
|
||||||
@@ -17,6 +18,9 @@ type ProductRelationDTO struct {
|
|||||||
ProductPrice float64 `gorm:"type:numeric(15,3);not null"`
|
ProductPrice float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
SellingPrice *float64 `gorm:"type:numeric(15,3)"`
|
SellingPrice *float64 `gorm:"type:numeric(15,3)"`
|
||||||
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
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"`
|
Flags *[]string `json:"flags,omitempty"`
|
||||||
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
||||||
Suppliers []ProductSupplierDTO `json:"suppliers"`
|
Suppliers []ProductSupplierDTO `json:"suppliers"`
|
||||||
@@ -31,6 +35,9 @@ type ProductListDTO struct {
|
|||||||
SellingPrice *float64 `json:"selling_price,omitempty"`
|
SellingPrice *float64 `json:"selling_price,omitempty"`
|
||||||
Tax *float64 `json:"tax,omitempty"`
|
Tax *float64 `json:"tax,omitempty"`
|
||||||
ExpiryPeriod *int `json:"expiry_period,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"`
|
Flags []string `json:"flags"`
|
||||||
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
||||||
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
||||||
@@ -59,6 +66,13 @@ func ToProductRelationDTO(e entity.Product) ProductRelationDTO {
|
|||||||
for i, f := range e.Flags {
|
for i, f := range e.Flags {
|
||||||
flags[i] = f.Name
|
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
|
var uomRef *uomDTO.UomRelationDTO
|
||||||
if e.Uom.Id != 0 {
|
if e.Uom.Id != 0 {
|
||||||
@@ -77,6 +91,9 @@ func ToProductRelationDTO(e entity.Product) ProductRelationDTO {
|
|||||||
Name: e.Name,
|
Name: e.Name,
|
||||||
ProductPrice: e.ProductPrice,
|
ProductPrice: e.ProductPrice,
|
||||||
SellingPrice: e.SellingPrice,
|
SellingPrice: e.SellingPrice,
|
||||||
|
Flag: flag,
|
||||||
|
SubFlag: subFlag,
|
||||||
|
SubFlags: subFlagsRef,
|
||||||
Flags: &flags,
|
Flags: &flags,
|
||||||
Uom: uomRef,
|
Uom: uomRef,
|
||||||
ProductCategory: categoryRef,
|
ProductCategory: categoryRef,
|
||||||
@@ -101,6 +118,7 @@ func ToProductListDTO(e entity.Product) ProductListDTO {
|
|||||||
for i, f := range e.Flags {
|
for i, f := range e.Flags {
|
||||||
flags[i] = f.Name
|
flags[i] = f.Name
|
||||||
}
|
}
|
||||||
|
flag, subFlag, subFlags := resolveProductFlagAndSubFlags(flags)
|
||||||
|
|
||||||
var uomRef *uomDTO.UomRelationDTO
|
var uomRef *uomDTO.UomRelationDTO
|
||||||
if e.Uom.Id != 0 {
|
if e.Uom.Id != 0 {
|
||||||
@@ -111,6 +129,9 @@ func ToProductListDTO(e entity.Product) ProductListDTO {
|
|||||||
return ProductListDTO{
|
return ProductListDTO{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
Name: e.Name,
|
Name: e.Name,
|
||||||
|
Flag: flag,
|
||||||
|
SubFlag: subFlag,
|
||||||
|
SubFlags: subFlags,
|
||||||
Flags: flags,
|
Flags: flags,
|
||||||
Uom: uomRef,
|
Uom: uomRef,
|
||||||
Brand: e.Brand,
|
Brand: e.Brand,
|
||||||
@@ -141,6 +162,58 @@ 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 {
|
func toProductSupplierDTOs(relations []entity.ProductSupplier) []ProductSupplierDTO {
|
||||||
if len(relations) == 0 {
|
if len(relations) == 0 {
|
||||||
return make([]ProductSupplierDTO, 0)
|
return make([]ProductSupplierDTO, 0)
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ type productService struct {
|
|||||||
Repository repository.ProductRepository
|
Repository repository.ProductRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var depletionProductFlags = []string{
|
||||||
|
string(utils.FlagAyamAfkir),
|
||||||
|
string(utils.FlagAyamCulling),
|
||||||
|
string(utils.FlagAyamMati),
|
||||||
|
}
|
||||||
|
|
||||||
func normalizeProductFlags(raw []string) ([]string, error) {
|
func normalizeProductFlags(raw []string) ([]string, error) {
|
||||||
normalized, invalid := utils.NormalizeFlagsForGroup(raw, utils.FlagGroupProduct)
|
normalized, invalid := utils.NormalizeFlagsForGroup(raw, utils.FlagGroupProduct)
|
||||||
if len(invalid) > 0 {
|
if len(invalid) > 0 {
|
||||||
@@ -41,6 +47,159 @@ func normalizeProductFlags(raw []string) ([]string, error) {
|
|||||||
return utils.FlagTypesToStrings(normalized), nil
|
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)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
normalizedOut, normalizeErr := normalizeProductFlags(out)
|
||||||
|
if normalizeErr != nil {
|
||||||
|
return nil, false, normalizeErr
|
||||||
|
}
|
||||||
|
return normalizedOut, 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)...)
|
||||||
|
normalizedOut, normalizeErr := normalizeProductFlags(out)
|
||||||
|
if normalizeErr != nil {
|
||||||
|
return nil, false, normalizeErr
|
||||||
|
}
|
||||||
|
return normalizedOut, 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 {
|
func NewProductService(repo repository.ProductRepository, validate *validator.Validate) ProductService {
|
||||||
return &productService{
|
return &productService{
|
||||||
Log: utils.Log,
|
Log: utils.Log,
|
||||||
@@ -70,12 +229,32 @@ func (s productService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity
|
|||||||
|
|
||||||
products, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
products, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
||||||
db = s.withRelations(db)
|
db = s.withRelations(db)
|
||||||
|
// Depletion master products are system products and often stored with is_visible = false.
|
||||||
|
// When requested explicitly via is_depletion=true, include hidden records.
|
||||||
|
if params.IsDepletion == nil || !*params.IsDepletion {
|
||||||
db = db.Where("is_visible = ?", true)
|
db = db.Where("is_visible = ?", true)
|
||||||
|
}
|
||||||
if params.Search != "" {
|
if params.Search != "" {
|
||||||
return db.Where("name ILIKE ?", "%"+params.Search+"%")
|
db = db.Where("name ILIKE ?", "%"+params.Search+"%")
|
||||||
}
|
}
|
||||||
if params.ProductCategoryID != 0 {
|
if params.ProductCategoryID != 0 {
|
||||||
return db.Where("product_category_id = ?", params.ProductCategoryID)
|
db = db.Where("product_category_id = ?", params.ProductCategoryID)
|
||||||
|
}
|
||||||
|
if params.IsDepletion != nil {
|
||||||
|
existsQuery := `
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM flags f
|
||||||
|
WHERE f.flagable_type = ?
|
||||||
|
AND f.flagable_id = products.id
|
||||||
|
AND UPPER(f.name) IN ?
|
||||||
|
)
|
||||||
|
`
|
||||||
|
if *params.IsDepletion {
|
||||||
|
db = db.Where(existsQuery, entity.FlagableTypeProduct, depletionProductFlags)
|
||||||
|
} else {
|
||||||
|
db = db.Where("NOT "+existsQuery, entity.FlagableTypeProduct, depletionProductFlags)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return db.Order("created_at DESC").Order("updated_at DESC")
|
return db.Order("created_at DESC").Order("updated_at DESC")
|
||||||
})
|
})
|
||||||
@@ -177,7 +356,7 @@ func (s *productService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
productFlags, flagErr := normalizeProductFlags(req.Flags)
|
productFlags, flagErr := resolveCreateProductFlags(req)
|
||||||
if flagErr != nil {
|
if flagErr != nil {
|
||||||
return nil, flagErr
|
return nil, flagErr
|
||||||
}
|
}
|
||||||
@@ -337,14 +516,11 @@ func (s productService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
|||||||
flagUpdate bool
|
flagUpdate bool
|
||||||
flagValues []string
|
flagValues []string
|
||||||
)
|
)
|
||||||
if req.Flags != nil {
|
|
||||||
flagUpdate = true
|
|
||||||
var flagErr error
|
var flagErr error
|
||||||
flagValues, flagErr = normalizeProductFlags(*req.Flags)
|
flagUpdate, flagValues, flagErr = resolveUpdateProductFlags(req)
|
||||||
if flagErr != nil {
|
if flagErr != nil {
|
||||||
return nil, flagErr
|
return nil, flagErr
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if len(updateBody) == 0 && !supplierUpdate && !flagUpdate {
|
if len(updateBody) == 0 && !supplierUpdate && !flagUpdate {
|
||||||
return s.GetOne(c, id)
|
return s.GetOne(c, id)
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ type Create struct {
|
|||||||
Tax *float64 `json:"tax,omitempty" validate:"omitempty"`
|
Tax *float64 `json:"tax,omitempty" validate:"omitempty"`
|
||||||
ExpiryPeriod *int `json:"expiry_period,omitempty" validate:"omitempty,gt=0"`
|
ExpiryPeriod *int `json:"expiry_period,omitempty" validate:"omitempty,gt=0"`
|
||||||
Suppliers []SupplierPrice `json:"suppliers,omitempty" validate:"omitempty,dive"`
|
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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +33,9 @@ type Update struct {
|
|||||||
Tax *float64 `json:"tax,omitempty" validate:"omitempty"`
|
Tax *float64 `json:"tax,omitempty" validate:"omitempty"`
|
||||||
ExpiryPeriod *int `json:"expiry_period,omitempty" validate:"omitempty,gt=0"`
|
ExpiryPeriod *int `json:"expiry_period,omitempty" validate:"omitempty,gt=0"`
|
||||||
Suppliers *[]SupplierPrice `json:"suppliers,omitempty" validate:"omitempty,dive"`
|
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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,4 +44,5 @@ type Query struct {
|
|||||||
Limit int `query:"limit" validate:"omitempty,number,min=1"`
|
Limit int `query:"limit" validate:"omitempty,number,min=1"`
|
||||||
Search string `query:"search" validate:"omitempty,max=50"`
|
Search string `query:"search" validate:"omitempty,max=50"`
|
||||||
ProductCategoryID int `query:"product_category_id" validate:"omitempty,number,min=1"`
|
ProductCategoryID int `query:"product_category_id" validate:"omitempty,number,min=1"`
|
||||||
|
IsDepletion *bool `query:"is_depletion" validate:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,26 +190,27 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
|
|||||||
}
|
}
|
||||||
|
|
||||||
if productWarehouse.Product.Id != 0 {
|
if productWarehouse.Product.Id != 0 {
|
||||||
|
category := strings.ToUpper(strings.TrimSpace(projectFlockKandang.ProjectFlock.Category))
|
||||||
var requiredFlag utils.FlagType
|
if category != string(utils.ProjectFlockCategoryGrowing) && category != string(utils.ProjectFlockCategoryLaying) {
|
||||||
if projectFlockKandang.ProjectFlock.Category == string(utils.ProjectFlockCategoryGrowing) {
|
|
||||||
requiredFlag = utils.FlagDOC
|
|
||||||
} else if projectFlockKandang.ProjectFlock.Category == string(utils.ProjectFlockCategoryLaying) {
|
|
||||||
requiredFlag = utils.FlagPullet
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("invalid flock category for chickin")
|
return nil, fmt.Errorf("invalid flock category for chickin")
|
||||||
}
|
}
|
||||||
|
|
||||||
hasRequiredFlag := false
|
hasAyamFlag := false
|
||||||
for _, flag := range productWarehouse.Product.Flags {
|
for _, flag := range productWarehouse.Product.Flags {
|
||||||
if utils.FlagType(flag.Name) == requiredFlag {
|
if utils.CanonicalFlagType(flag.Name) == utils.FlagAyam {
|
||||||
hasRequiredFlag = true
|
hasAyamFlag = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasRequiredFlag {
|
if !hasAyamFlag {
|
||||||
return nil, fmt.Errorf("product warehouse %d cannot be used for %s chickin. Product must have %s flag (product ID: %d, warehouse ID: %d)", chickinReq.ProductWarehouseId, projectFlockKandang.ProjectFlock.Category, requiredFlag, productWarehouse.Product.Id, productWarehouse.Id)
|
return nil, fmt.Errorf(
|
||||||
|
"product warehouse %d cannot be used for %s chickin. Product must have AYAM flag (or legacy alias DOC/PULLET/LAYER) (product ID: %d, warehouse ID: %d)",
|
||||||
|
chickinReq.ProductWarehouseId,
|
||||||
|
projectFlockKandang.ProjectFlock.Category,
|
||||||
|
productWarehouse.Product.Id,
|
||||||
|
productWarehouse.Id,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -11,12 +12,6 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
chickinOutFunctionCode = "CHICKIN_OUT"
|
|
||||||
chickinUsableLane = "USABLE"
|
|
||||||
chickinSourceTable = "project_chickins"
|
|
||||||
)
|
|
||||||
|
|
||||||
func reflowChickinScope(
|
func reflowChickinScope(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
fifoStockV2Svc commonSvc.FifoStockV2Service,
|
fifoStockV2Svc commonSvc.FifoStockV2Service,
|
||||||
@@ -62,9 +57,6 @@ func resolveChickinFlagGroupByProductWarehouse(ctx context.Context, tx *gorm.DB,
|
|||||||
Select("rr.flag_group_code").
|
Select("rr.flag_group_code").
|
||||||
Joins("JOIN fifo_stock_v2_flag_groups fg ON fg.code = rr.flag_group_code AND fg.is_active = TRUE").
|
Joins("JOIN fifo_stock_v2_flag_groups fg ON fg.code = rr.flag_group_code AND fg.is_active = TRUE").
|
||||||
Where("rr.is_active = TRUE").
|
Where("rr.is_active = TRUE").
|
||||||
Where("rr.lane = ?", chickinUsableLane).
|
|
||||||
Where("rr.function_code = ?", chickinOutFunctionCode).
|
|
||||||
Where("rr.source_table = ?", chickinSourceTable).
|
|
||||||
Where(`
|
Where(`
|
||||||
EXISTS (
|
EXISTS (
|
||||||
SELECT 1
|
SELECT 1
|
||||||
@@ -76,10 +68,13 @@ func resolveChickinFlagGroupByProductWarehouse(ctx context.Context, tx *gorm.DB,
|
|||||||
AND fm.flag_group_code = rr.flag_group_code
|
AND fm.flag_group_code = rr.flag_group_code
|
||||||
)
|
)
|
||||||
`, productWarehouseID, entity.FlagableTypeProduct).
|
`, productWarehouseID, entity.FlagableTypeProduct).
|
||||||
Order("rr.id ASC").
|
Order("fg.priority ASC, rr.id ASC").
|
||||||
Limit(1).
|
Limit(1).
|
||||||
Take(&selected).Error
|
Take(&selected).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+179
-4
@@ -14,9 +14,17 @@ type FlagType string
|
|||||||
|
|
||||||
type FlagGroup string
|
type FlagGroup string
|
||||||
|
|
||||||
|
type ProductFlagOption struct {
|
||||||
|
Flag FlagType `json:"flag"`
|
||||||
|
SubFlags []FlagType `json:"sub_flags"`
|
||||||
|
AllowWithoutSubFlag bool `json:"allow_without_sub_flag"`
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FlagIsActive FlagType = "IS_ACTIVE"
|
FlagIsActive FlagType = "IS_ACTIVE"
|
||||||
|
|
||||||
|
FlagAyam FlagType = "AYAM"
|
||||||
|
|
||||||
FlagDOC FlagType = "DOC"
|
FlagDOC FlagType = "DOC"
|
||||||
FlagPullet FlagType = "PULLET"
|
FlagPullet FlagType = "PULLET"
|
||||||
FlagLayer FlagType = "LAYER"
|
FlagLayer FlagType = "LAYER"
|
||||||
@@ -41,6 +49,8 @@ const (
|
|||||||
FlagTelurPecah FlagType = "TELUR-PECAH"
|
FlagTelurPecah FlagType = "TELUR-PECAH"
|
||||||
FlagTelurPutih FlagType = "TELUR-PUTIH"
|
FlagTelurPutih FlagType = "TELUR-PUTIH"
|
||||||
FlagTelurRetak FlagType = "TELUR-RETAK"
|
FlagTelurRetak FlagType = "TELUR-RETAK"
|
||||||
|
FlagTelurPapacal FlagType = "TELUR-PAPACAL"
|
||||||
|
FlagTelurJumbo FlagType = "TELUR-JUMBO"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -50,9 +60,10 @@ const (
|
|||||||
|
|
||||||
var flagGroupOptions = map[FlagGroup][]FlagType{
|
var flagGroupOptions = map[FlagGroup][]FlagType{
|
||||||
FlagGroupProduct: {
|
FlagGroupProduct: {
|
||||||
FlagDOC,
|
FlagAyam,
|
||||||
FlagPullet,
|
FlagAyamAfkir,
|
||||||
FlagLayer,
|
FlagAyamCulling,
|
||||||
|
FlagAyamMati,
|
||||||
FlagPakan,
|
FlagPakan,
|
||||||
FlagPreStarter,
|
FlagPreStarter,
|
||||||
FlagStarter,
|
FlagStarter,
|
||||||
@@ -61,12 +72,75 @@ var flagGroupOptions = map[FlagGroup][]FlagType{
|
|||||||
FlagObat,
|
FlagObat,
|
||||||
FlagVitamin,
|
FlagVitamin,
|
||||||
FlagKimia,
|
FlagKimia,
|
||||||
|
FlagTelur,
|
||||||
|
FlagTelurUtuh,
|
||||||
|
FlagTelurPecah,
|
||||||
|
FlagTelurPutih,
|
||||||
|
FlagTelurRetak,
|
||||||
|
FlagTelurPapacal,
|
||||||
|
FlagTelurJumbo,
|
||||||
},
|
},
|
||||||
FlagGroupNonstock: {
|
FlagGroupNonstock: {
|
||||||
FlagEkspedisi,
|
FlagEkspedisi,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var productMainFlags = []FlagType{
|
||||||
|
FlagAyam,
|
||||||
|
FlagPakan,
|
||||||
|
FlagOVK,
|
||||||
|
FlagTelur,
|
||||||
|
}
|
||||||
|
|
||||||
|
var productSubFlagsByFlag = map[FlagType][]FlagType{
|
||||||
|
FlagAyam: {
|
||||||
|
FlagAyamAfkir,
|
||||||
|
FlagAyamCulling,
|
||||||
|
FlagAyamMati,
|
||||||
|
},
|
||||||
|
FlagPakan: {
|
||||||
|
FlagPreStarter,
|
||||||
|
FlagStarter,
|
||||||
|
FlagFinisher,
|
||||||
|
},
|
||||||
|
FlagOVK: {
|
||||||
|
FlagObat,
|
||||||
|
FlagVitamin,
|
||||||
|
FlagKimia,
|
||||||
|
},
|
||||||
|
FlagTelur: {
|
||||||
|
FlagTelurUtuh,
|
||||||
|
FlagTelurPutih,
|
||||||
|
FlagTelurRetak,
|
||||||
|
FlagTelurPecah,
|
||||||
|
FlagTelurPapacal,
|
||||||
|
FlagTelurJumbo,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var productSubFlagToFlag = func() map[FlagType]FlagType {
|
||||||
|
out := make(map[FlagType]FlagType)
|
||||||
|
for flag, subFlags := range productSubFlagsByFlag {
|
||||||
|
for _, subFlag := range subFlags {
|
||||||
|
out[subFlag] = flag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}()
|
||||||
|
|
||||||
|
var productAllowWithoutSubFlagByFlag = map[FlagType]bool{
|
||||||
|
FlagAyam: true,
|
||||||
|
FlagPakan: false,
|
||||||
|
FlagOVK: false,
|
||||||
|
FlagTelur: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
var legacyFlagTypeAliases = map[FlagType]FlagType{
|
||||||
|
FlagDOC: FlagAyam,
|
||||||
|
FlagPullet: FlagAyam,
|
||||||
|
FlagLayer: FlagAyam,
|
||||||
|
}
|
||||||
|
|
||||||
var allFlagTypes = func() map[FlagType]struct{} {
|
var allFlagTypes = func() map[FlagType]struct{} {
|
||||||
m := map[FlagType]struct{}{
|
m := map[FlagType]struct{}{
|
||||||
FlagIsActive: {},
|
FlagIsActive: {},
|
||||||
@@ -83,6 +157,102 @@ func AllFlagTypes() map[FlagType]struct{} {
|
|||||||
return allFlagTypes
|
return allFlagTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func canonicalizeFlagType(flag FlagType) FlagType {
|
||||||
|
if canonical, ok := legacyFlagTypeAliases[flag]; ok {
|
||||||
|
return canonical
|
||||||
|
}
|
||||||
|
return flag
|
||||||
|
}
|
||||||
|
|
||||||
|
func CanonicalFlagType(v string) FlagType {
|
||||||
|
normalized := FlagType(strings.ToUpper(strings.TrimSpace(v)))
|
||||||
|
if normalized == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return canonicalizeFlagType(normalized)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LegacyFlagTypeAliases() map[FlagType]FlagType {
|
||||||
|
out := make(map[FlagType]FlagType, len(legacyFlagTypeAliases))
|
||||||
|
for legacy, canonical := range legacyFlagTypeAliases {
|
||||||
|
out[legacy] = canonical
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProductMainFlags() []FlagType {
|
||||||
|
out := make([]FlagType, len(productMainFlags))
|
||||||
|
copy(out, productMainFlags)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProductSubFlagsByFlag() map[FlagType][]FlagType {
|
||||||
|
out := make(map[FlagType][]FlagType, len(productSubFlagsByFlag))
|
||||||
|
for flag, subFlags := range productSubFlagsByFlag {
|
||||||
|
dup := make([]FlagType, len(subFlags))
|
||||||
|
copy(dup, subFlags)
|
||||||
|
out[flag] = dup
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProductSubFlagToFlag() map[FlagType]FlagType {
|
||||||
|
out := make(map[FlagType]FlagType, len(productSubFlagToFlag))
|
||||||
|
for subFlag, flag := range productSubFlagToFlag {
|
||||||
|
out[subFlag] = flag
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProductFlagOptions() []ProductFlagOption {
|
||||||
|
result := make([]ProductFlagOption, 0, len(productMainFlags))
|
||||||
|
for _, flag := range productMainFlags {
|
||||||
|
subFlags := productSubFlagsByFlag[flag]
|
||||||
|
dup := make([]FlagType, len(subFlags))
|
||||||
|
copy(dup, subFlags)
|
||||||
|
result = append(result, ProductFlagOption{
|
||||||
|
Flag: flag,
|
||||||
|
SubFlags: dup,
|
||||||
|
AllowWithoutSubFlag: productAllowWithoutSubFlagByFlag[flag],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProductFlagAllowWithoutSubFlag(flag FlagType) bool {
|
||||||
|
canonical := canonicalizeFlagType(flag)
|
||||||
|
allow, ok := productAllowWithoutSubFlagByFlag[canonical]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return allow
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsProductMainFlag(flag FlagType) bool {
|
||||||
|
canonical := canonicalizeFlagType(flag)
|
||||||
|
for _, f := range productMainFlags {
|
||||||
|
if f == canonical {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidProductSubFlag(flag FlagType, subFlag FlagType) bool {
|
||||||
|
canonicalFlag := canonicalizeFlagType(flag)
|
||||||
|
canonicalSubFlag := canonicalizeFlagType(subFlag)
|
||||||
|
allowedSubFlags, ok := productSubFlagsByFlag[canonicalFlag]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, allowed := range allowedSubFlags {
|
||||||
|
if allowed == canonicalSubFlag {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// WarehouseType
|
// WarehouseType
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
@@ -621,7 +791,11 @@ const (
|
|||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
func IsValidFlagType(v string) bool {
|
func IsValidFlagType(v string) bool {
|
||||||
_, ok := allFlagTypes[FlagType(strings.ToUpper(strings.TrimSpace(v)))]
|
flag := FlagType(strings.ToUpper(strings.TrimSpace(v)))
|
||||||
|
if _, ok := allFlagTypes[flag]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
_, ok := legacyFlagTypeAliases[flag]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,6 +841,7 @@ func NormalizeFlagTypes(flags []string) []FlagType {
|
|||||||
if normalized == "" {
|
if normalized == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
normalized = canonicalizeFlagType(normalized)
|
||||||
if _, exists := seen[normalized]; exists {
|
if _, exists := seen[normalized]; exists {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user