Upstream sync
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/notificationservice"
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain/service"
|
||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||
)
|
||||
@@ -30,8 +31,10 @@ type Service struct {
|
||||
// New returns a new domain Service instance
|
||||
func New(svc *service.Service, mapper *entitymapping.Mapper, notification *notificationservice.Service, cfg *config.Config) *Service {
|
||||
once.Do(func() {
|
||||
bcbsi := bcbsi.New(cfg)
|
||||
|
||||
instance = &Service{
|
||||
Users: newUserService(svc, mapper),
|
||||
Users: newUserService(svc, mapper, bcbsi, cfg),
|
||||
Rides: newRideService(svc, mapper),
|
||||
Visits: newVisitService(svc, mapper),
|
||||
Provider: newProviderService(svc, mapper),
|
||||
|
||||
@@ -1,24 +1,40 @@
|
||||
package applicationservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"html"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi"
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain/service"
|
||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
|
||||
"bitbucket.org/nemt/nemt-portal-api/server/validation"
|
||||
"googlemaps.github.io/maps"
|
||||
)
|
||||
|
||||
// userService holds methods to user application service
|
||||
type userService struct {
|
||||
svc *service.Service
|
||||
mapEntity *entitymapping.Mapper
|
||||
bcbsi *bcbsi.Service
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
// newUserService returns a userService instance
|
||||
func newUserService(svc *service.Service, mapper *entitymapping.Mapper) *userService {
|
||||
func newUserService(svc *service.Service, mapper *entitymapping.Mapper, bcbsi *bcbsi.Service, cfg *config.Config) *userService {
|
||||
return &userService{
|
||||
svc: svc,
|
||||
mapEntity: mapper,
|
||||
bcbsi: bcbsi,
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,3 +200,215 @@ func (s *userService) RemoveContact(contact viewmodel.Contact) (retVal viewmodel
|
||||
|
||||
return s.mapEntity.User.ToContactModel(entity), err
|
||||
}
|
||||
|
||||
func (s *userService) rangeIn(low, hi int) string {
|
||||
result := low + rand.Intn(hi-low)
|
||||
return fmt.Sprintf("%v", result)
|
||||
}
|
||||
|
||||
func (s *userService) generatePassword(n int) string {
|
||||
const (
|
||||
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
)
|
||||
|
||||
return s.stringWithCharset(n, charset)
|
||||
}
|
||||
|
||||
func (s *userService) 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 (s *userService) CheckAndCreateMember(user viewmodel.User, provider viewmodel.ProviderResp, authorUser viewmodel.User) (viewmodel.User, error) {
|
||||
if validationErrors := validation.ValidateEligibility(&user); len(validationErrors) > 0 {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: "Eligibility validation failed", Errors: validationErrors}
|
||||
}
|
||||
|
||||
entityUser := s.mapEntity.User.ToUserEntity(user)
|
||||
entityAuthorUser := s.mapEntity.User.ToUserEntity(authorUser)
|
||||
entityProvider := s.mapEntity.Provider.ToProviderRespEntity(provider)
|
||||
|
||||
newEmail := entityUser.Email
|
||||
newPhoneNumber := entityUser.PhoneNumber
|
||||
|
||||
var err error
|
||||
|
||||
if entityUser.UUID != "" {
|
||||
entityUser, err = s.svc.Users.GetByUUID(entityUser.UUID, "US")
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error finding user by UUID: %s", err.Error())}
|
||||
}
|
||||
} else {
|
||||
entityUser, err = s.svc.Users.GetByMemberID(entityUser.Member)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error finding user by Subscriber ID: %s", err.Error())}
|
||||
}
|
||||
}
|
||||
|
||||
var eligibility viewmodel.Eligibility
|
||||
loc, _ := time.LoadLocation("America/Chicago")
|
||||
eligibility.TrackingID = s.rangeIn(1000000, 9999999)
|
||||
eligibility.ServiceInfo.DateOfService = time.Now().In(loc)
|
||||
eligibility.ServiceInfo.ServiceTypeCodes = []string{"30"}
|
||||
|
||||
if entityProvider.InternalID == "" && entityProvider.ProviderUUID != "" {
|
||||
entityProvider, err = s.svc.Provider.GetByUUID(entityProvider.ProviderUUID, entityAuthorUser)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error finding provider by UUID: %s", err.Error())}
|
||||
}
|
||||
} else {
|
||||
entityProvider, err = s.svc.Provider.GetByNPI(entityProvider.InternalID, entityAuthorUser)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error finding provider by NPI: %s", err.Error())}
|
||||
}
|
||||
}
|
||||
|
||||
if entityProvider.InternalID == "" {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: "Provider not found"}
|
||||
} else {
|
||||
eligibility.Provider.ProviderNPI = entityProvider.InternalID
|
||||
eligibility.Provider.ProviderName = entityProvider.OrganizatioName
|
||||
}
|
||||
|
||||
plan, err := s.svc.Plans.GetByAlphaPrefix(entityUser.Member[:3])
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error finding Plan: %s", err.Error())}
|
||||
}
|
||||
eligibility.Payer.PayerID = fmt.Sprintf("%v", plan.PayerID)
|
||||
eligibility.Payer.PayerName = plan.PayerName
|
||||
|
||||
eligibility.Subscriber.SubscriberID = entityUser.Member
|
||||
eligibility.Subscriber.PatientType = entityUser.Type
|
||||
eligibility.Subscriber.Name.First = strings.Split(entityUser.Name, " ")[0]
|
||||
eligibility.Subscriber.Name.Last = strings.Split(entityUser.Name, " ")[1]
|
||||
eligibility.Subscriber.DemographicInfo.DateOfBirth = entityUser.BirthDate
|
||||
eligibility.Subscriber.DemographicInfo.Gender = entityUser.Gender
|
||||
|
||||
ret, err := s.bcbsi.BXE.CheckEligibility(eligibility)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error checking eligibility: %s", err.Error())}
|
||||
}
|
||||
|
||||
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 {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error unmarshaling 271 response: %s", err.Error())}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if len(strings.TrimSpace(zipCode)) > 5 {
|
||||
zipCode = strings.TrimSpace(zipCode)[:5]
|
||||
}
|
||||
|
||||
if !s.cfg.App.DisableZipValidation {
|
||||
_, err = s.svc.Zipcodes.GetByParticipatingZipcode(zipCode)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Member's Home zipcode, %s, is not currently eligible for participation in this program", zipCode)}
|
||||
}
|
||||
}
|
||||
|
||||
if entityUser.ID == 0 {
|
||||
profile, err := s.svc.Profile.GetByKey("US")
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error getting user profile: %s", err.Error())}
|
||||
}
|
||||
entityUser.Profiles = append(entityUser.Profiles, profile)
|
||||
|
||||
if len(entityUser.PhoneNumber) == 10 && !strings.Contains(entityUser.PhoneNumber, "+1") {
|
||||
phoneNumber := fmt.Sprintf("+1%s", entityUser.PhoneNumber)
|
||||
entityUser.PhoneNumber = phoneNumber
|
||||
}
|
||||
|
||||
entityUser.Test = false
|
||||
entityUser, err = s.svc.Users.Create(entityUser)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error creating user: %s", err.Error())}
|
||||
}
|
||||
} else {
|
||||
if len(newEmail) > 0 && newEmail != entityUser.Email {
|
||||
entityUser.Email = newEmail
|
||||
}
|
||||
|
||||
if len(newPhoneNumber) > 0 && len(newPhoneNumber) == 10 && !strings.Contains(newPhoneNumber, "+1") {
|
||||
newPhoneNumber = fmt.Sprintf("+1%s", newPhoneNumber)
|
||||
}
|
||||
|
||||
if len(newPhoneNumber) > 0 && len(newPhoneNumber) == 12 && strings.Contains(newPhoneNumber, "+1") {
|
||||
entityUser.PhoneNumber = newPhoneNumber
|
||||
}
|
||||
|
||||
err = s.svc.Users.UpdateLogin(entityUser)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error updating login data: %s", err.Error())}
|
||||
}
|
||||
}
|
||||
|
||||
address := entity.Address{}
|
||||
address.AddressType = entity.Params{
|
||||
Key: "home",
|
||||
Name: "Home",
|
||||
}
|
||||
address.Name = fmt.Sprintf("%s, %s", header.N301, body.N401)
|
||||
address.Address = fmt.Sprintf("%s, %s (%s)", header.N301, body.N401, zipCode)
|
||||
address.CreatedUser = entityAuthorUser
|
||||
address.User = entityUser
|
||||
address.Origin = entity.Params{
|
||||
Key: "provider",
|
||||
Name: "Provider",
|
||||
}
|
||||
|
||||
googleMapsAPI, err := maps.NewClient(maps.WithClientIDAndSignature("gme-bluecrossandblue1", "msqgD-jdqCyR0M_1u5C1HION5iI="))
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error instanciating google maps: %s", err.Error())}
|
||||
}
|
||||
|
||||
r := &maps.GeocodingRequest{
|
||||
Address: address.Address + " " + body.N402 + ", " + zipCode,
|
||||
}
|
||||
|
||||
result, err := googleMapsAPI.Geocode(context.Background(), r)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error getting geocode info: %s", err.Error())}
|
||||
}
|
||||
|
||||
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 := s.svc.Users.RemoveAddress(a.UUID)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error removing old address: %s", err.Error())}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
address, err = s.svc.Users.SaveAddress(address)
|
||||
if err != nil {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: fmt.Sprintf("Error saving new address: %s", err.Error())}
|
||||
}
|
||||
entityUser.Addresses = append(entityUser.Addresses, address)
|
||||
|
||||
return s.mapEntity.User.ToUserModel(entityUser), nil
|
||||
} else {
|
||||
return viewmodel.User{}, &viewmodel.ValidationError{Message: "No benefits found for the member"}
|
||||
}
|
||||
|
||||
return viewmodel.User{}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user