package usecases import ( "cargo-erp-backend/internal/domain" "cargo-erp-backend/internal/handlers/dto" "cargo-erp-backend/pkg/datatable" "cargo-erp-backend/pkg/helpers" "fmt" "reflect" "time" "gorm.io/gorm" ) type BasicPricingUsecaseInterface interface { GetAll(filter dto.BasicPricingFilterAllRequest) ([]dto.CreateBasicPricingResponse, int64, error) GetList(dto.DataTableRequest) (dto.DataTableResponse, error) GetByID(id string) (dto.CreateBasicPricingResponse, error) Create(req dto.CreateBasicPricingRequest, createdBy string, merchantid *string) (dto.CreateBasicPricingResponse, error) Update(id string, req dto.CreateBasicPricingRequest, updatedBy string) (dto.CreateBasicPricingResponse, error) Delete(id string) error } type BasicPricingUsecase struct { Helper helpers.HelperInterface AuthUser domain.User } func NewBasicPricingUsecase(helper helpers.HelperInterface, authUser domain.User) BasicPricingUsecaseInterface { return &BasicPricingUsecase{Helper: helper, AuthUser: authUser} } func (u *BasicPricingUsecase) loadComponents(pricingIDs []string) (map[string][]domain.BasicPricingComponent, error) { if len(pricingIDs) == 0 { return make(map[string][]domain.BasicPricingComponent), nil } var components []domain.BasicPricingComponent db := u.Helper.GetDB("slave") if err := db.Where("basic_pricing_id IN ?", pricingIDs).Find(&components).Error; err != nil { return nil, err } componentsMap := make(map[string][]domain.BasicPricingComponent) for _, c := range components { if c.BasicPricingID != nil { componentsMap[*c.BasicPricingID] = append(componentsMap[*c.BasicPricingID], c) } } return componentsMap, nil } func (u *BasicPricingUsecase) toResponse(pricing domain.BasicPricing, components []domain.BasicPricingComponent) dto.CreateBasicPricingResponse { resp := dto.CreateBasicPricingResponse{ ID: pricing.ID, ProvinceSourceID: pricing.ProvinceSourceID, CitySourceID: pricing.CitySourceID, DistrictSourceID: pricing.DistrictSourceID, SubdistrictSourceID: pricing.SubdistrictSourceID, PostalCodeSourceID: pricing.PostalCodeSourceID, ProvinceDestinationID: pricing.ProvinceDestinationID, CityDestinationID: pricing.CityDestinationID, DistrictDestinationID: pricing.DistrictDestinationID, SubdistrictDestinationID: pricing.SubdistrictDestinationID, PostalCodeDestinationID: pricing.PostalCodeDestinationID, PackageTypeID: pricing.PackageTypeID, ModaID: pricing.ModaID, MerchantID: pricing.MerchantID, } resp.Components = make([]dto.BasicPricingComponentResponse, 0, len(components)) for _, c := range components { resp.Components = append(resp.Components, dto.BasicPricingComponentResponse{ ID: c.ID, CostComponentID: c.CostComponentID, Value: c.Value, }) } return resp } func (u *BasicPricingUsecase) GetAll(filter dto.BasicPricingFilterAllRequest) ([]dto.CreateBasicPricingResponse, int64, error) { var pricings []domain.BasicPricing var total int64 db := u.Helper.GetDB("slave") tx := db.Model(&pricings) if u.AuthUser.UsersRole_Relation == nil || u.AuthUser.UsersRole_Relation.RoleKey != "SPM" { tx.Where(db.Where("merchant_id IS NULL").Or("merchant_id=?", u.AuthUser.MerchantID)) } v := reflect.ValueOf(filter) t := reflect.TypeOf(filter) for i := 0; i < v.NumField(); i++ { if v.Field(i).String() != "" { tagKey := t.Field(i).Tag.Get("form") tx.Where(fmt.Sprintf("%v=?", tagKey), v.Field(i)) } } tx.Model(&domain.BasicPricing{}).Count(&total) tx.Order("name ASC") if err := tx.Find(&pricings).Error; err != nil { return nil, 0, err } pricingIDs := make([]string, 0, len(pricings)) for _, p := range pricings { pricingIDs = append(pricingIDs, p.ID) } componentsMap, err := u.loadComponents(pricingIDs) if err != nil { return nil, 0, err } responses := make([]dto.CreateBasicPricingResponse, 0, len(pricings)) for _, p := range pricings { components := componentsMap[p.ID] responses = append(responses, u.toResponse(p, components)) } return responses, total, nil } func (u *BasicPricingUsecase) GetList(req dto.DataTableRequest) (dto.DataTableResponse, error) { var response dto.DataTableResponse db := u.Helper.GetDB("slave") tx := db.Table("basic_pricing"). Joins("LEFT JOIN province AS ps ON basic_pricing.province_source_id=ps.id"). Joins("LEFT JOIN city AS cs ON basic_pricing.city_source_id=cs.id"). Joins("LEFT JOIN province AS pd ON basic_pricing.province_destination_id=pd.id"). Joins("LEFT JOIN city AS cd ON basic_pricing.city_destination_id=cd.id"). Joins("LEFT JOIN merchant ON basic_pricing.merchant_id=merchant.id") dt := datatable.NewDatatable(tx, req) coldef := make([]dto.DataTableColDef, 0) coldef = append(coldef, dto.DataTableColDef{ Field: "basic_pricing.name", Alias: "name", }) coldef = append(coldef, dto.DataTableColDef{ Field: "basic_pricing.id", Alias: "id", }) response = dt.Render(coldef) return response, nil } func (u *BasicPricingUsecase) GetByID(id string) (dto.CreateBasicPricingResponse, error) { var pricing domain.BasicPricing db := u.Helper.GetDB("slave") if err := db.Where("id = ?", id).First(&pricing).Error; err != nil { return dto.CreateBasicPricingResponse{}, err } var components []domain.BasicPricingComponent if err := db.Where("basic_pricing_id = ?", id).Find(&components).Error; err != nil { return dto.CreateBasicPricingResponse{}, err } return u.toResponse(pricing, components), nil } func (u *BasicPricingUsecase) Create(req dto.CreateBasicPricingRequest, createdBy string, merchantid *string) (dto.CreateBasicPricingResponse, error) { now := time.Now() db := u.Helper.GetDB("master") var pricing domain.BasicPricing var savedComponents []domain.BasicPricingComponent err := db.Transaction(func(tx *gorm.DB) error { pricing = domain.BasicPricing{ Name: &req.Name, ProvinceSourceID: strPtr(req.ProvinceSourceID), CitySourceID: strPtr(req.CitySourceID), DistrictSourceID: strPtr(req.DistrictSourceID), SubdistrictSourceID: strPtr(req.SubdistrictSourceID), PostalCodeSourceID: strPtr(req.PostalCodeSourceID), ProvinceDestinationID: strPtr(req.ProvinceDestinationID), CityDestinationID: strPtr(req.CityDestinationID), DistrictDestinationID: strPtr(req.DistrictDestinationID), SubdistrictDestinationID: strPtr(req.SubdistrictDestinationID), PostalCodeDestinationID: strPtr(req.PostalCodeDestinationID), PackageTypeID: strPtr(req.PackageTypeID), ModaID: strPtr(req.ModaID), MerchantID: merchantid, CreatedBy: &createdBy, CreatedOn: &now, UpdatedBy: &createdBy, UpdatedOn: &now, } if err := tx.Create(&pricing).Error; err != nil { return err } for _, comp := range req.Components { c := domain.BasicPricingComponent{ BasicPricingID: &pricing.ID, CostComponentID: &comp.CostComponentID, Value: &comp.Value, } if err := tx.Create(&c).Error; err != nil { return err } savedComponents = append(savedComponents, c) } return nil }) if err != nil { return dto.CreateBasicPricingResponse{}, err } return u.toResponse(pricing, savedComponents), nil } func (u *BasicPricingUsecase) Update(id string, req dto.CreateBasicPricingRequest, updatedBy string) (dto.CreateBasicPricingResponse, error) { db := u.Helper.GetDB("master") var pricing domain.BasicPricing var savedComponents []domain.BasicPricingComponent err := db.Transaction(func(tx *gorm.DB) error { q := tx if u.AuthUser.UsersRole_Relation == nil || u.AuthUser.UsersRole_Relation.RoleKey != "SPM" { q = tx.Where("merchant_id=?", u.AuthUser.MerchantID) } if err := q.Where("id = ?", id).First(&pricing).Error; err != nil { return err } now := time.Now() pricing.Name = &req.Name pricing.ProvinceSourceID = strPtr(req.ProvinceSourceID) pricing.CitySourceID = strPtr(req.CitySourceID) pricing.DistrictSourceID = strPtr(req.DistrictSourceID) pricing.SubdistrictSourceID = strPtr(req.SubdistrictSourceID) pricing.PostalCodeSourceID = strPtr(req.PostalCodeSourceID) pricing.ProvinceDestinationID = strPtr(req.ProvinceDestinationID) pricing.CityDestinationID = strPtr(req.CityDestinationID) pricing.DistrictDestinationID = strPtr(req.DistrictDestinationID) pricing.SubdistrictDestinationID = strPtr(req.SubdistrictDestinationID) pricing.PostalCodeDestinationID = strPtr(req.PostalCodeDestinationID) pricing.PackageTypeID = strPtr(req.PackageTypeID) pricing.ModaID = strPtr(req.ModaID) pricing.UpdatedBy = &updatedBy pricing.UpdatedOn = &now if err := tx.Save(&pricing).Error; err != nil { return err } if err := tx.Where("basic_pricing_id = ?", id).Delete(&domain.BasicPricingComponent{}).Error; err != nil { return err } for _, comp := range req.Components { c := domain.BasicPricingComponent{ BasicPricingID: &pricing.ID, CostComponentID: &comp.CostComponentID, Value: &comp.Value, } if err := tx.Create(&c).Error; err != nil { return err } savedComponents = append(savedComponents, c) } return nil }) if err != nil { return dto.CreateBasicPricingResponse{}, err } return u.toResponse(pricing, savedComponents), nil } func (u *BasicPricingUsecase) Delete(id string) error { db := u.Helper.GetDB("master") return db.Transaction(func(tx *gorm.DB) error { q := tx if u.AuthUser.UsersRole_Relation == nil || u.AuthUser.UsersRole_Relation.RoleKey != "SPM" { q = tx.Where("merchant_id=?", u.AuthUser.MerchantID) } var pricing domain.BasicPricing if err := q.Where("id = ?", id).First(&pricing).Error; err != nil { return err } if err := tx.Where("basic_pricing_id = ?", id).Delete(&domain.BasicPricingComponent{}).Error; err != nil { return err } if err := tx.Delete(&pricing).Error; err != nil { return err } return nil }) } func strPtr(s string) *string { if s == "" { return nil } return &s }