feat[BE]: Refactor Chickin create and approvals support chickin growing and chickin laying, and create get one project flock kandang API

This commit is contained in:
aguhh18
2025-11-02 21:06:03 +07:00
parent 219a6a39ed
commit 20f1be2ef8
21 changed files with 1002 additions and 206 deletions
@@ -0,0 +1,76 @@
package controller
import (
"math"
"strconv"
"gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/dto"
service "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/services"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/validations"
"gitlab.com/mbugroup/lti-api.git/internal/response"
"github.com/gofiber/fiber/v2"
)
type ProjectFlockKandangController struct {
ProjectFlockKandangService service.ProjectFlockKandangService
}
func NewProjectFlockKandangController(projectFlockKandangService service.ProjectFlockKandangService) *ProjectFlockKandangController {
return &ProjectFlockKandangController{
ProjectFlockKandangService: projectFlockKandangService,
}
}
func (u *ProjectFlockKandangController) GetAll(c *fiber.Ctx) error {
query := &validation.Query{
Page: c.QueryInt("page", 1),
Limit: c.QueryInt("limit", 10),
Search: c.Query("search", ""),
}
if query.Page < 1 || query.Limit < 1 {
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
}
result, totalResults, err := u.ProjectFlockKandangService.GetAll(c, query)
if err != nil {
return err
}
return c.Status(fiber.StatusOK).
JSON(response.SuccessWithPaginate[dto.ProjectFlockKandangListDTO]{
Code: fiber.StatusOK,
Status: "success",
Message: "Get all projectFlockKandangs successfully",
Meta: response.Meta{
Page: query.Page,
Limit: query.Limit,
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
TotalResults: totalResults,
},
Data: dto.ToProjectFlockKandangListDTOs(result),
})
}
func (u *ProjectFlockKandangController) GetOne(c *fiber.Ctx) error {
param := c.Params("id")
id, err := strconv.Atoi(param)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
}
result, availableQtys, err := u.ProjectFlockKandangService.GetOne(c, uint(id))
if err != nil {
return err
}
return c.Status(fiber.StatusOK).
JSON(response.Success{
Code: fiber.StatusOK,
Status: "success",
Message: "Get projectFlockKandang successfully",
Data: dto.ToProjectFlockKandangListDTOWithAvailableQty(*result, availableQtys),
})
}
@@ -0,0 +1,353 @@
package dto
import (
"time"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
areaDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto"
fcrDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/dto"
flockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/dto"
kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto"
chickinDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/dto"
projectFlockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/dto"
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
)
type ProjectFlockKandangBaseDTO struct {
Id uint `json:"id"`
}
type ProjectFlockCustomDTO struct {
Id uint `json:"id"`
Period int `json:"period"`
Flock *flockDTO.FlockBaseDTO `json:"flock,omitempty"`
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"`
Category string `json:"category"`
Fcr *fcrDTO.FcrBaseDTO `json:"fcr,omitempty"`
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"`
Kandangs []kandangDTO.KandangBaseDTO `json:"kandangs,omitempty"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type KandangCustomDTO struct {
Id uint `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
}
type ProductBaseDTO struct {
Id uint `json:"id"`
Name string `json:"name"`
}
type WarehouseBaseDTO struct {
Id uint `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
}
type ProductWarehouseDTO struct {
Id uint `json:"id"`
Quantity float64 `json:"quantity"`
Product *ProductBaseDTO `json:"product,omitempty"`
Warehouse *WarehouseBaseDTO `json:"warehouse,omitempty"`
}
type AvailableQtyDTO struct {
ProductWarehouse *ProductWarehouseDTO `json:"product_warehouse,omitempty"`
}
type ProjectFlockKandangListDTO struct {
ProjectFlockKandangBaseDTO
ProjectFlock *ProjectFlockCustomDTO `json:"project_flock,omitempty"`
Kandang *KandangCustomDTO `json:"kandang,omitempty"`
Chickins []chickinDTO.ChickinBaseDTO `json:"chickins,omitempty"`
AvailableQtys []AvailableQtyDTO `json:"available_qtys,omitempty"`
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"`
Approval *approvalDTO.ApprovalBaseDTO `json:"approval,omitempty"`
}
type ProjectFlockKandangDetailDTO struct {
ProjectFlockKandangListDTO
}
func ToProjectFlockKandangBaseDTO(e entity.ProjectFlockKandang) ProjectFlockKandangBaseDTO {
return ProjectFlockKandangBaseDTO{
Id: e.Id,
}
}
func toProjectFlockCustomDTO(pf *projectFlockDTO.ProjectFlockListDTO) *ProjectFlockCustomDTO {
if pf == nil {
return nil
}
return &ProjectFlockCustomDTO{
Id: pf.Id,
Period: pf.Period,
Flock: pf.Flock,
Area: pf.Area,
Category: pf.Category,
Fcr: pf.Fcr,
Location: pf.Location,
Kandangs: pf.Kandangs,
CreatedUser: pf.CreatedUser,
CreatedAt: pf.CreatedAt,
UpdatedAt: pf.UpdatedAt,
}
}
func buildAvailableQtys(chickins []entity.ProjectChickin) []AvailableQtyDTO {
if len(chickins) == 0 {
return nil
}
availableQtyMap := make(map[uint]AvailableQtyDTO)
for _, ch := range chickins {
if ch.ProductWarehouse == nil || ch.ProductWarehouse.Quantity <= 0 {
continue
}
if _, exists := availableQtyMap[ch.ProductWarehouseId]; exists {
continue
}
pwDTO := &ProductWarehouseDTO{
Id: ch.ProductWarehouse.Id,
Quantity: ch.ProductWarehouse.Quantity,
}
if ch.ProductWarehouse.Product.Id != 0 {
pwDTO.Product = &ProductBaseDTO{
Id: ch.ProductWarehouse.Product.Id,
Name: ch.ProductWarehouse.Product.Name,
}
}
if ch.ProductWarehouse.Warehouse.Id != 0 {
pwDTO.Warehouse = &WarehouseBaseDTO{
Id: ch.ProductWarehouse.Warehouse.Id,
Name: ch.ProductWarehouse.Warehouse.Name,
Type: ch.ProductWarehouse.Warehouse.Type,
}
}
availableQtyMap[ch.ProductWarehouseId] = AvailableQtyDTO{
ProductWarehouse: pwDTO,
}
}
if len(availableQtyMap) == 0 {
return nil
}
result := make([]AvailableQtyDTO, 0, len(availableQtyMap))
for _, v := range availableQtyMap {
result = append(result, v)
}
return result
}
func buildChickins(chickins []entity.ProjectChickin) []chickinDTO.ChickinBaseDTO {
if len(chickins) == 0 {
return nil
}
result := make([]chickinDTO.ChickinBaseDTO, len(chickins))
for i, ch := range chickins {
result[i] = chickinDTO.ToChickinBaseDTO(ch)
}
return result
}
func defaultProjectFlockKandangLatestApproval(e entity.ProjectFlockKandang) *approvalDTO.ApprovalBaseDTO {
if e.LatestApproval != nil {
result := approvalDTO.ToApprovalDTO(*e.LatestApproval)
return &result
}
return nil
}
func ToProjectFlockKandangListDTO(e entity.ProjectFlockKandang) ProjectFlockKandangListDTO {
var projectFlockSummary *projectFlockDTO.ProjectFlockListDTO
if e.ProjectFlock.Id != 0 {
mapped := projectFlockDTO.ToProjectFlockListDTO(e.ProjectFlock)
projectFlockSummary = &mapped
}
var kandangSummary *KandangCustomDTO
if e.Kandang.Id != 0 {
kandangSummary = &KandangCustomDTO{
Id: e.Kandang.Id,
Name: e.Kandang.Name,
Status: e.Kandang.Status,
}
}
var createdUser *userDTO.UserBaseDTO
if e.ProjectFlock.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.ProjectFlock.CreatedUser)
createdUser = &mapped
} else if e.ProjectFlock.CreatedBy != 0 {
mapped := userDTO.UserBaseDTO{Id: e.ProjectFlock.CreatedBy, IdUser: int64(e.ProjectFlock.CreatedBy)}
createdUser = &mapped
}
return ProjectFlockKandangListDTO{
ProjectFlockKandangBaseDTO: ToProjectFlockKandangBaseDTO(e),
ProjectFlock: toProjectFlockCustomDTO(projectFlockSummary),
Kandang: kandangSummary,
Chickins: buildChickins(e.Chickins),
AvailableQtys: buildAvailableQtys(e.Chickins),
CreatedAt: e.CreatedAt,
CreatedUser: createdUser,
Approval: defaultProjectFlockKandangLatestApproval(e),
}
}
func ToProjectFlockKandangListDTOs(e []entity.ProjectFlockKandang) []ProjectFlockKandangListDTO {
result := make([]ProjectFlockKandangListDTO, len(e))
for i, r := range e {
result[i] = ToProjectFlockKandangListDTO(r)
}
return result
}
func ToProjectFlockKandangDetailDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDetailDTO {
return ProjectFlockKandangDetailDTO{
ProjectFlockKandangListDTO: ToProjectFlockKandangListDTO(e),
}
}
func ToProjectFlockKandangListDTOWithAvailableQty(e entity.ProjectFlockKandang, availableQtysRaw []map[string]interface{}) ProjectFlockKandangListDTO {
var projectFlockSummary *projectFlockDTO.ProjectFlockListDTO
if e.ProjectFlock.Id != 0 {
mapped := projectFlockDTO.ToProjectFlockListDTO(e.ProjectFlock)
projectFlockSummary = &mapped
}
var kandangSummary *KandangCustomDTO
if e.Kandang.Id != 0 {
kandangSummary = &KandangCustomDTO{
Id: e.Kandang.Id,
Name: e.Kandang.Name,
Status: e.Kandang.Status,
}
}
var createdUser *userDTO.UserBaseDTO
if e.ProjectFlock.CreatedUser.Id != 0 {
mapped := userDTO.ToUserBaseDTO(e.ProjectFlock.CreatedUser)
createdUser = &mapped
} else if e.ProjectFlock.CreatedBy != 0 {
mapped := userDTO.UserBaseDTO{Id: e.ProjectFlock.CreatedBy, IdUser: int64(e.ProjectFlock.CreatedBy)}
createdUser = &mapped
}
// convert available qtys from raw map data
var availableQtys []AvailableQtyDTO
if len(availableQtysRaw) > 0 {
availableQtys = buildAvailableQtysFromRaw(availableQtysRaw)
}
return ProjectFlockKandangListDTO{
ProjectFlockKandangBaseDTO: ToProjectFlockKandangBaseDTO(e),
ProjectFlock: toProjectFlockCustomDTO(projectFlockSummary),
Kandang: kandangSummary,
Chickins: buildChickins(e.Chickins),
AvailableQtys: availableQtys,
CreatedAt: e.CreatedAt,
CreatedUser: createdUser,
Approval: defaultProjectFlockKandangLatestApproval(e),
}
}
func buildAvailableQtysFromRaw(availableQtysRaw []map[string]interface{}) []AvailableQtyDTO {
if len(availableQtysRaw) == 0 {
return nil
}
result := make([]AvailableQtyDTO, len(availableQtysRaw))
for i, v := range availableQtysRaw {
pwData, ok := v["product_warehouse"].(map[string]interface{})
if !ok {
continue
}
pwDTO := buildProductWarehouseFromMap(pwData)
result[i] = AvailableQtyDTO{
ProductWarehouse: pwDTO,
}
}
return result
}
func buildProductWarehouseFromMap(pwData map[string]interface{}) *ProductWarehouseDTO {
if pwData == nil {
return nil
}
dto := &ProductWarehouseDTO{}
if id, ok := pwData["id"].(float64); ok {
dto.Id = uint(id)
} else if id, ok := pwData["id"].(uint); ok {
dto.Id = id
}
if qty, ok := pwData["quantity"].(float64); ok {
dto.Quantity = qty
}
if pData, ok := pwData["product"].(map[string]interface{}); ok {
dto.Product = buildProductFromMap(pData)
}
if wData, ok := pwData["warehouse"].(map[string]interface{}); ok {
dto.Warehouse = buildWarehouseFromMap(wData)
}
return dto
}
func buildProductFromMap(pData map[string]interface{}) *ProductBaseDTO {
if pData == nil {
return nil
}
product := &ProductBaseDTO{}
if id, ok := pData["id"].(float64); ok {
product.Id = uint(id)
} else if id, ok := pData["id"].(uint); ok {
product.Id = id
}
if name, ok := pData["name"].(string); ok {
product.Name = name
}
return product
}
func buildWarehouseFromMap(wData map[string]interface{}) *WarehouseBaseDTO {
if wData == nil {
return nil
}
warehouse := &WarehouseBaseDTO{}
if id, ok := wData["id"].(float64); ok {
warehouse.Id = uint(id)
} else if id, ok := wData["id"].(uint); ok {
warehouse.Id = id
}
if name, ok := wData["name"].(string); ok {
warehouse.Name = name
}
if wType, ok := wData["type"].(string); ok {
warehouse.Type = wType
}
return warehouse
}
@@ -0,0 +1,42 @@
package project_flock_kandangs
import (
"fmt"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
sProjectFlockKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/services"
rProjectFlockKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories"
sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
)
type ProjectFlockKandangModule struct{}
func (ProjectFlockKandangModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
projectFlockKandangRepo := rProjectFlockKandang.NewProjectFlockKandangRepository(db)
userRepo := rUser.NewUserRepository(db)
warehouseRepo := rWarehouse.NewWarehouseRepository(db)
productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db)
approvalRepo := commonRepo.NewApprovalRepository(db)
approvalService := commonSvc.NewApprovalService(approvalRepo)
// register workflow steps for project flock kandang approvals
if err := approvalService.RegisterWorkflowSteps(utils.ApprovalWorkflowProjectFlockKandang, utils.ProjectFlockKandangApprovalSteps); err != nil {
panic(fmt.Sprintf("failed to register project flock kandang approval workflow: %v", err))
}
projectFlockKandangService := sProjectFlockKandang.NewProjectFlockKandangService(projectFlockKandangRepo, approvalService, warehouseRepo, productWarehouseRepo, validate)
userService := sUser.NewUserService(userRepo, validate)
ProjectFlockKandangRoutes(router, userService, projectFlockKandangService)
}
@@ -0,0 +1,26 @@
package project_flock_kandangs
import (
// m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
controller "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/controllers"
projectFlockKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/services"
user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
"github.com/gofiber/fiber/v2"
)
func ProjectFlockKandangRoutes(v1 fiber.Router, u user.UserService, s projectFlockKandang.ProjectFlockKandangService) {
ctrl := controller.NewProjectFlockKandangController(s)
route := v1.Group("/project-flock-kandangs")
// route.Get("/", m.Auth(u), ctrl.GetAll)
// route.Post("/", m.Auth(u), ctrl.CreateOne)
// route.Get("/:id", m.Auth(u), ctrl.GetOne)
// route.Patch("/:id", m.Auth(u), ctrl.UpdateOne)
// route.Delete("/:id", m.Auth(u), ctrl.DeleteOne)
route.Get("/", ctrl.GetAll)
route.Get("/:id", ctrl.GetOne)
}
@@ -0,0 +1,147 @@
package service
import (
"errors"
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/validations"
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
type ProjectFlockKandangService interface {
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandang, int64, error)
GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, []map[string]interface{}, error)
}
type projectFlockKandangService struct {
Log *logrus.Logger
Validate *validator.Validate
Repository repository.ProjectFlockKandangRepository
ApprovalSvc commonSvc.ApprovalService
WarehouseRepo rWarehouse.WarehouseRepository
ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository
}
func NewProjectFlockKandangService(repo repository.ProjectFlockKandangRepository, approvalSvc commonSvc.ApprovalService, warehouseRepo rWarehouse.WarehouseRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, validate *validator.Validate) ProjectFlockKandangService {
return &projectFlockKandangService{
Log: utils.Log,
Validate: validate,
Repository: repo,
ApprovalSvc: approvalSvc,
WarehouseRepo: warehouseRepo,
ProductWarehouseRepo: productWarehouseRepo,
}
}
func (s projectFlockKandangService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandang, int64, error) {
if err := s.Validate.Struct(params); err != nil {
return nil, 0, err
}
projectFlockKandangs, err := s.Repository.GetAll(c.Context())
if err != nil {
s.Log.Errorf("Failed to get projectFlockKandangs: %+v", err)
return nil, 0, err
}
total := int64(len(projectFlockKandangs))
return projectFlockKandangs, total, nil
}
func (s projectFlockKandangService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, []map[string]interface{}, error) {
projectFlockKandang, err := s.Repository.GetByID(c.Context(), id)
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil, fiber.NewError(fiber.StatusNotFound, "ProjectFlockKandang not found")
}
if err != nil {
s.Log.Errorf("Failed get projectFlockKandang by id: %+v", err)
return nil, nil, err
}
if len(projectFlockKandang.Chickins) > 0 && s.ApprovalSvc != nil {
latest, err := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandang.Id, nil)
if err != nil {
s.Log.Errorf("Failed to fetch latest kandang approval for projectFlockKandang %d: %+v", projectFlockKandang.Id, err)
}
if latest != nil {
projectFlockKandang.LatestApproval = latest
}
}
availableQtys, err := s.getAvailableQuantities(c, projectFlockKandang)
if err != nil {
s.Log.Errorf("Failed to fetch available quantities for kandang %d: %+v", projectFlockKandang.Kandang.Id, err)
availableQtys = nil
}
return projectFlockKandang, availableQtys, nil
}
func (s projectFlockKandangService) getAvailableQuantities(c *fiber.Ctx, projectFlockKandang *entity.ProjectFlockKandang) ([]map[string]interface{}, error) {
if projectFlockKandang.Kandang.Id == 0 || s.WarehouseRepo == nil || s.ProductWarehouseRepo == nil {
return nil, nil
}
warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), projectFlockKandang.Kandang.Id)
if err != nil || warehouse == nil {
return nil, nil
}
var productCategoryCode string
if projectFlockKandang.ProjectFlock.Category == string(utils.ProjectFlockCategoryGrowing) {
productCategoryCode = "DOC"
} else if projectFlockKandang.ProjectFlock.Category == string(utils.ProjectFlockCategoryLaying) {
productCategoryCode = "PULLET"
} else {
return nil, nil
}
products, err := s.ProductWarehouseRepo.GetByCategoryCodeAndWarehouseID(c.Context(), productCategoryCode, warehouse.Id)
if err != nil || len(products) == 0 {
return nil, nil
}
var result []map[string]interface{}
for _, pw := range products {
if pw.Quantity > 0 {
// Build product data
productData := map[string]interface{}{
"id": pw.Product.Id,
"name": pw.Product.Name,
}
// Build warehouse data
warehouseData := map[string]interface{}{
"id": pw.Warehouse.Id,
"name": pw.Warehouse.Name,
"type": pw.Warehouse.Type,
}
// Build product warehouse data with nested product and warehouse
productWarehouseData := map[string]interface{}{
"id": pw.Id,
"quantity": pw.Quantity,
"product": productData,
"warehouse": warehouseData,
}
result = append(result, map[string]interface{}{
"available_qty": pw.Quantity,
"product_warehouse": productWarehouseData,
})
}
}
return result, nil
}
@@ -0,0 +1,17 @@
package validation
type Create struct {
ProjectFlockId uint `json:"project_flock_id" validate:"required"`
KandangId uint `json:"kandang_id" validate:"required"`
}
type Update struct {
ProjectFlockId *uint `json:"project_flock_id,omitempty" validate:"omitempty"`
KandangId *uint `json:"kandang_id,omitempty" validate:"omitempty"`
}
type Query struct {
Page int `query:"page" validate:"omitempty,number,min=1,gt=0"`
Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"`
Search string `query:"search" validate:"omitempty,max=50"`
}