package eligibilityroute import ( "context" "encoding/xml" "fmt" "html" "math/rand" "strings" "sync" "time" "bitbucket.org/nemt/nemt-portal-api/application/applicationservice" "bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi" "bitbucket.org/nemt/nemt-portal-api/application/viewmodel" "bitbucket.org/nemt/nemt-portal-api/infra/auth" "bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/server/router/routeutils" "github.com/labstack/echo" "googlemaps.github.io/maps" ) var ( instance *controller once sync.Once ) type controller struct { cfg *config.Config svc *applicationservice.Service bcbsi *bcbsi.Service } func controllerInstance(cfg *config.Config, svc *applicationservice.Service) *controller { once.Do(func() { instance = &controller{ cfg: cfg, svc: svc, bcbsi: bcbsi.New(cfg), } }) return instance } func (c *controller) rangeIn(low, hi int) string { result := low + rand.Intn(hi-low) return fmt.Sprintf("%v", result) } func (c *controller) generatePassword(n int) string { const ( charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ) return c.stringWithCharset(n, charset) } func (c *controller) stringWithCharset(length int, charset string) string { b := make([]byte, length) var seededRand *rand.Rand = rand.New( rand.NewSource(time.Now().UnixNano())) for i := range b { b[i] = charset[seededRand.Intn(len(charset))] } return string(b) } func (c *controller) handleEligibility(ctx echo.Context) error { var eligibility viewmodel.Eligibility if err := ctx.Bind(&eligibility); err != nil { return routeutils.HandleAPIError(ctx, err) } authUser, err := auth.GetUserDetail(ctx, c.cfg) if err != nil { return routeutils.HandleAPIError(ctx, err) } if eligibility.Provider.ProviderNPI == "" { provider, err := c.svc.Provider.GetByOrganization(authUser.Profiles[0].Organization.UUID, authUser) if err != nil { return routeutils.HandleAPIError(ctx, err) } eligibility.Provider.ProviderNPI = provider.InternalID eligibility.Provider.ProviderName = provider.OrganizatioName } loc, _ := time.LoadLocation("America/Chicago") eligibility.TrackingID = c.rangeIn(1000000, 9999999) eligibility.ServiceInfo.DateOfService = time.Now().In(loc) eligibility.ServiceInfo.ServiceTypeCodes = []string{"30"} var plan viewmodel.Plan if eligibility.Subscriber.SubscriberID != "" { plan, err = c.svc.Plan.GetByAlphaPrefix(eligibility.Subscriber.SubscriberID[:3]) if err != nil { return routeutils.HandleAPIError(ctx, err) } eligibility.Payer.PayerID = fmt.Sprintf("%v", plan.PayerID) eligibility.Payer.PayerName = plan.PayerName } else { return routeutils.ResponseAPIFieldValidationError(ctx, "subscriber_id", "member # is required.") } ret, err := c.bcbsi.BXE.CheckEligibility(eligibility) if err != nil { fmt.Println("Error Here: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } if ret.QueryResult.QueryResultSummary.BenefitsFound { xmlString := html.UnescapeString(ret.QueryResult.HIPPA271.T271) xmlReader := strings.NewReader(xmlString) var f viewmodel.Interchange271 err = xml.NewDecoder(xmlReader).Decode(&f) if err != nil { fmt.Println("Error to unmarshal: ", err.Error()) } user, err := c.svc.Users.GetByMemberID(eligibility.Subscriber.SubscriberID) if err != nil { fmt.Println(err) return routeutils.HandleAPIError(ctx, err) } if user.ID == "" { user.Pass = c.generatePassword(8) user.BirthDate = &eligibility.Subscriber.DemographicInfo.DateOfBirth user.Member = &eligibility.Subscriber.SubscriberID user.Gender = &eligibility.Subscriber.DemographicInfo.Gender user.First = eligibility.Subscriber.Name.First user.Last = eligibility.Subscriber.Name.Last user.Active = true user.Type = &eligibility.Subscriber.PatientType user.PhoneNumber = eligibility.User.PhoneNumber user.Email = eligibility.User.Email profile, err := c.svc.Profile.GetByKey("US") if err != nil { return routeutils.HandleAPIError(ctx, err) } user.Profiles = append(user.Profiles, profile) if user.BirthDate == nil || user.BirthDate.IsZero() { return routeutils.ResponseAPIAuthError(ctx, "birthdate is required", false) } if user.Member == nil || len(*user.Member) == 0 { return routeutils.ResponseAPIAuthError(ctx, "member is required", false) } if user.Gender == nil || len(*user.Gender) == 0 || (*user.Gender != "M" && *user.Gender != "F" && *user.Gender != "U") { return routeutils.ResponseAPIAuthError(ctx, "gender is required", false) } if len(user.Name) == 0 && len(user.First) == 0 && len(user.Last) == 0 { return routeutils.ResponseAPIAuthError(ctx, "name is required", false) } if len(user.First) != 0 && len(user.Last) != 0 { user.Name = fmt.Sprintf("%s %s", user.First, user.Last) } if user.PhoneNumber != nil && len(*user.PhoneNumber) == 10 && !strings.Contains(*user.PhoneNumber, "+1") { phoneNumber := fmt.Sprintf("+1%s", *user.PhoneNumber) user.PhoneNumber = &phoneNumber } else { return routeutils.ResponseAPIFieldValidationError(ctx, "phonenumber", "Phone number is required") } user, err = c.svc.Users.Create(user, authUser) if err != nil { return routeutils.HandleAPIError(ctx, err) } } else { if eligibility.User.Email != nil && len(*eligibility.User.Email) > 0 { user.Email = eligibility.User.Email } if eligibility.User.PhoneNumber != nil { if len(*eligibility.User.PhoneNumber) == 10 && !strings.Contains(*eligibility.User.PhoneNumber, "+1") { phoneNumber := fmt.Sprintf("+1%s", *eligibility.User.PhoneNumber) eligibility.User.PhoneNumber = &phoneNumber } if len(*eligibility.User.PhoneNumber) > 0 { user.PhoneNumber = eligibility.User.PhoneNumber } } err = c.svc.Users.UpdateLogin(user) if err != nil { return routeutils.HandleAPIError(ctx, err) } } address := viewmodel.Address{} header := f.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N3_0950 body := f.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N4_0960 zipCode := strings.TrimSpace(body.N403) address.AddressTypeName = "Home" address.AddressType = "home" address.Name = fmt.Sprintf("%s, %s", header.N301, body.N401) address.Address = fmt.Sprintf("%s, %s (%s)", header.N301, body.N401, zipCode) address.CreatedUserUUID = authUser.ID address.User = user address.Type = "provider" googleMapsAPI, err := maps.NewClient(maps.WithClientIDAndSignature("gme-bluecrossandblue1", "msqgD-jdqCyR0M_1u5C1HION5iI=")) if err != nil { fmt.Println("Error to instantiate googles api: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } r := &maps.GeocodingRequest{ Address: address.Address + " " + body.N402 + ", " + zipCode, } result, err := googleMapsAPI.Geocode(context.Background(), r) if err != nil { fmt.Println("Error to instantiate googles api: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } if len(result) > 0 { address.Latitude = result[0].Geometry.Location.Lat address.Longitude = result[0].Geometry.Location.Lng } if len(user.Addresses) > 0 { for _, a := range user.Addresses { if a.AddressType == "home" { err := c.svc.Users.RemoveAddress(a.UUID) if err != nil { fmt.Println("Error to remove old address: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } } } } address, err = c.svc.Users.SaveAddress(address) if err != nil { fmt.Println("Error to save address: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } user.Addresses = append(user.Addresses, address) return ctx.JSON(200, user) } else { return routeutils.ResponseAPINotEligibleWithMessageError(ctx, "No benefits found for member") } }