454 lines
14 KiB
Go
454 lines
14 KiB
Go
package datamysql
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
|
|
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
|
|
"github.com/go-sql-driver/mysql"
|
|
uuid "github.com/satori/go.uuid"
|
|
)
|
|
|
|
// rideRepo maps methods to database
|
|
type providerRepo struct {
|
|
conn executor
|
|
}
|
|
|
|
func newProviderRepo(conn executor) *providerRepo {
|
|
return &providerRepo{
|
|
conn: conn,
|
|
}
|
|
}
|
|
|
|
func (c *providerRepo) getProfileQuery(user entity.User) (query string, where string, err error) {
|
|
if len(user.Profiles) > 0 {
|
|
for _, p := range user.Profiles {
|
|
switch p.Key {
|
|
case "AD", "BCBSIAD", "BDCAD", "PLANAD":
|
|
return
|
|
case "SP", "SPT":
|
|
switch p.Organization.Type.Key {
|
|
case "techsupport", "bcbsi", "bcbsa", "plan":
|
|
return
|
|
case "provider":
|
|
query = ` INNER JOIN viw_organization_provider c
|
|
ON a.provider_id = c.provider_id `
|
|
where = fmt.Sprintf(` AND (c.organization_uuid = '%s' OR c.parent_organization_uuid = '%s') `, p.Organization.UUID, p.Organization.UUID)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
if query == "" && where == "" {
|
|
return "", "", fmt.Errorf("Invalid Query")
|
|
} else {
|
|
return
|
|
}
|
|
} else {
|
|
return "", "", fmt.Errorf("User has no profile to search")
|
|
}
|
|
}
|
|
|
|
func (c *providerRepo) getSelectQueryBaseKey() string {
|
|
return `SELECT
|
|
a.provider_key_id,
|
|
a.provider_id,
|
|
a.internal_id,
|
|
a.internal_id_suffix,
|
|
a.location_seq_num,
|
|
a.plan_code,
|
|
a.product_id,
|
|
a.treatment_category_code,
|
|
a.active,
|
|
a.enabled,
|
|
a.create_at,
|
|
a.update_at,
|
|
a.created_user
|
|
FROM tab_provider_key a `
|
|
}
|
|
|
|
func (c *providerRepo) getSelectQueryBase() string {
|
|
return `SELECT DISTINCT
|
|
a.provider_id,
|
|
a.provider_uuid,
|
|
a.provider_internal_id,
|
|
IFNULL(a.provider_internal_id_suffix, '') provider_internal_id_suffix,
|
|
IFNULL(a.provider_muk_id, '') provider_muk_id,
|
|
IFNULL(a.organization_name, '') organization_name,
|
|
IFNULL(a.gender, '') gender,
|
|
IFNULL(a.accept_new_patients, '') accept_new_patients,
|
|
IFNULL(a.provider_name, '') provider_name,
|
|
IFNULL(a.first_name, '') first_name,
|
|
IFNULL(a.last_name, '') last_name,
|
|
IFNULL(a.middle_name, '') middle_name,
|
|
IFNULL(a.provider_title, '') provider_title,
|
|
IFNULL(a.street_name1, '') street_name1,
|
|
IFNULL(a.street_name2, '') street_name2,
|
|
IFNULL(a.city_name, '') city_name,
|
|
IFNULL(a.state, '') state,
|
|
IFNULL(a.zipcode, '') zipcode,
|
|
IFNULL(a.country, '') country,
|
|
IFNULL(a.latitude, 0) latitude,
|
|
IFNULL(a.longitude, 0) longitude,
|
|
IFNULL(a.phone_number, '') phone_number,
|
|
a.create_at,
|
|
a.update_at,
|
|
a.active,
|
|
a.enabled,
|
|
a.created_user,
|
|
(3959 * acos (
|
|
cos ( radians(?) )
|
|
* cos( radians( IFNULL(a.latitude, 0) ) )
|
|
* cos( radians( IFNULL(a.longitude, 0) ) - radians(?) )
|
|
+ sin ( radians(?) )
|
|
* sin( radians( IFNULL(a.latitude, 0) ) )
|
|
)) AS distance_in_miles
|
|
FROM
|
|
tab_provider a
|
|
INNER JOIN tab_provider_key b
|
|
ON a.provider_id = b.provider_id `
|
|
}
|
|
|
|
func (c *providerRepo) GetAll(user entity.User) ([]entity.Provider, error) {
|
|
lat := 41.886406
|
|
long := -87.624225
|
|
|
|
query, where, err := c.getProfileQuery(user)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
query = c.getSelectQueryBase() + query + " WHERE 1 = 1 " + where
|
|
|
|
providers, err := c.parseSet(c.conn.Query(query, lat, long, lat))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c.getKeys("", "", providers)
|
|
}
|
|
|
|
func (c *providerRepo) GetByUUID(providerUUID string, user entity.User) (entity.Provider, error) {
|
|
lat := 41.886406
|
|
long := -87.624225
|
|
|
|
query, where, err := c.getProfileQuery(user)
|
|
if err != nil {
|
|
return entity.Provider{}, err
|
|
}
|
|
|
|
query = c.getSelectQueryBase() + query + " WHERE a.provider_uuid = ? " + where
|
|
|
|
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, providerUUID))
|
|
}
|
|
|
|
func (c *providerRepo) GetByMukID(mukID string, user entity.User) (entity.Provider, error) {
|
|
lat := 41.886406
|
|
long := -87.624225
|
|
|
|
query, where, err := c.getProfileQuery(user)
|
|
if err != nil {
|
|
return entity.Provider{}, err
|
|
}
|
|
|
|
query = c.getSelectQueryBase() + query + " WHERE a.provider_muk_id = ? " + where
|
|
|
|
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, mukID))
|
|
}
|
|
|
|
func (c *providerRepo) GetByNPI(NPI string, user entity.User) (entity.Provider, error) {
|
|
lat := 41.886406
|
|
long := -87.624225
|
|
|
|
query, where, err := c.getProfileQuery(user)
|
|
if err != nil {
|
|
return entity.Provider{}, err
|
|
}
|
|
|
|
query = c.getSelectQueryBase() + query + " WHERE a.provider_internal_id = ? " + where
|
|
|
|
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, NPI))
|
|
}
|
|
|
|
func (c *providerRepo) Get(query string, lat float64, long float64, distance int64, planCode string, productID string, mukID string, internalID string, sort string, user entity.User) ([]entity.Provider, error) {
|
|
filter := " WHERE 1 = 1 "
|
|
params := make([]interface{}, 0)
|
|
|
|
if lat == 0 && long == 0 {
|
|
lat = 41.886406
|
|
long = -87.624225
|
|
}
|
|
params = append(params, lat, long, lat)
|
|
|
|
if query != "" && (mukID == "" && internalID == "") {
|
|
filter += " AND (a.provider_name LIKE ? OR a.street_name1 LIKE ? OR a.street_name2 LIKE ? OR a.zipcode LIKE ?) "
|
|
// MATCH(a.provider_internal_id, a.provider_internal_id_suffix, a.provider_muk_id, a.provider_name, a.street_name1, a.street_name2, a.city_name, a.state, a.zipcode, a.country, a.phone_number) AGAINST (?)
|
|
|
|
query = "%" + query + "%"
|
|
params = append(params, query, query, query, query)
|
|
}
|
|
|
|
if planCode != "" {
|
|
filter += " AND b.plan_code = ? "
|
|
params = append(params, planCode)
|
|
}
|
|
|
|
if productID != "" {
|
|
filter += " AND b.product_id = ? "
|
|
params = append(params, productID)
|
|
}
|
|
|
|
if mukID != "" {
|
|
filter += " AND a.provider_muk_id = ? "
|
|
params = append(params, mukID)
|
|
}
|
|
|
|
if internalID != "" {
|
|
filter += " AND a.provider_internal_id = ? "
|
|
params = append(params, internalID)
|
|
}
|
|
|
|
final := " HAVING distance_in_miles < ? "
|
|
params = append(params, distance)
|
|
|
|
if sort == "name" {
|
|
final += " ORDER BY a.provider_name ASC "
|
|
} else if sort == "distance" {
|
|
final += " ORDER BY distance_in_miles ASC "
|
|
}
|
|
|
|
query, where, err := c.getProfileQuery(user)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
query = c.getSelectQueryBase() + query + filter + where + final
|
|
|
|
providers, err := c.parseSet(c.conn.Query(query, params...))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(providers) > 0 {
|
|
return c.getKeys(planCode, productID, providers)
|
|
} else {
|
|
return providers, nil
|
|
}
|
|
}
|
|
|
|
func (c *providerRepo) getKeys(planCode string, productID string, providers []entity.Provider) ([]entity.Provider, error) {
|
|
var params []interface{}
|
|
var queryParams = " WHERE a.provider_id IN ("
|
|
for _, p := range providers {
|
|
queryParams += "?,"
|
|
params = append(params, p.ProviderID)
|
|
}
|
|
queryParams = queryParams[0 : len(queryParams)-1]
|
|
queryParams += ") "
|
|
|
|
if planCode != "" {
|
|
queryParams += " AND a.plan_code = ? "
|
|
params = append(params, planCode)
|
|
}
|
|
|
|
if productID != "" {
|
|
queryParams += " AND a.product_id = ? "
|
|
params = append(params, productID)
|
|
}
|
|
|
|
keys, err := c.parseKeySet(c.conn.Query(c.getSelectQueryBaseKey()+queryParams, params...))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sortedResults := make(map[string][]entity.ProviderKey)
|
|
for _, k := range keys {
|
|
sortedKey := fmt.Sprintf("provider%v", k.Provider.ProviderID)
|
|
sortedResults[sortedKey] = append(sortedResults[sortedKey], k)
|
|
}
|
|
|
|
for i := range providers {
|
|
sortedKey := fmt.Sprintf("provider%v", providers[i].ProviderID)
|
|
providers[i].Keys = sortedResults[sortedKey]
|
|
}
|
|
|
|
return providers, nil
|
|
}
|
|
|
|
// parseSet parses a result set result to an entity array
|
|
func (c *providerRepo) parseKeySet(rows *sql.Rows, err error) ([]entity.ProviderKey, error) {
|
|
if err != nil {
|
|
return nil, errors.Wrap(err)
|
|
}
|
|
result := make([]entity.ProviderKey, 0)
|
|
for rows.Next() {
|
|
entity, err := c.parseKeyEntity(rows)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err)
|
|
}
|
|
result = append(result, entity)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// parseEntity parses a result to an entity
|
|
func (c *providerRepo) parseKeyEntity(row scanner) (retVal entity.ProviderKey, err error) {
|
|
err = row.Scan(
|
|
&retVal.ProviderKeyID, &retVal.Provider.ProviderID, &retVal.InternalID, &retVal.InternalSuffixID, &retVal.LocationSeqNumber, &retVal.PlanCode, &retVal.ProductID, &retVal.TreatmentCategoryCode, &retVal.Active, &retVal.Enabled, &retVal.CreateDate, &retVal.UpdateDate, &retVal.CreatedUser.ID)
|
|
|
|
return retVal, errors.Wrap(err)
|
|
}
|
|
|
|
// parseSet parses a result set result to an entity array
|
|
func (c *providerRepo) parseSet(rows *sql.Rows, err error) ([]entity.Provider, error) {
|
|
if err != nil {
|
|
return nil, errors.Wrap(err)
|
|
}
|
|
result := make([]entity.Provider, 0)
|
|
for rows.Next() {
|
|
entity, err := c.parseEntity(rows)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err)
|
|
}
|
|
result = append(result, entity)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// parseEntity parses a result to an entity
|
|
func (c *providerRepo) parseEntity(row scanner) (retVal entity.Provider, err error) {
|
|
err = row.Scan(
|
|
&retVal.ProviderID, &retVal.ProviderUUID, &retVal.InternalID, &retVal.InternalSuffixID, &retVal.MukID, &retVal.OrganizatioName, &retVal.Gender, &retVal.AcceptNewPatients, &retVal.Name, &retVal.FirstName, &retVal.LastName, &retVal.MiddleName, &retVal.Title, &retVal.Address.StreetAddress1, &retVal.Address.StreetAddress2, &retVal.Address.CityName, &retVal.Address.State, &retVal.Address.ZipCode, &retVal.Address.Country, &retVal.Address.Latitude, &retVal.Address.Longitude, &retVal.Address.PhoneNumber, &retVal.CreateDate, &retVal.UpdateDate, &retVal.Active, &retVal.Enabled, &retVal.CreatedUser.ID, &retVal.Distance)
|
|
|
|
if err == sql.ErrNoRows {
|
|
return retVal, nil
|
|
} else {
|
|
return retVal, errors.Wrap(err)
|
|
}
|
|
}
|
|
|
|
func (c *providerRepo) Save(providers []entity.ProviderResponse, user entity.User) ([]entity.Provider, error) {
|
|
var savedProviders = make([]entity.Provider, 0)
|
|
for _, p := range providers {
|
|
provider, err := c.saveProvider(p, user)
|
|
if err != nil {
|
|
if driverErr, ok := err.(*mysql.MySQLError); ok {
|
|
if driverErr.Number != 1062 {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
savedProviders = append(savedProviders, provider)
|
|
}
|
|
}
|
|
|
|
return savedProviders, nil
|
|
}
|
|
|
|
func (c *providerRepo) saveProvider(provider entity.ProviderResponse, user entity.User) (entity.Provider, error) {
|
|
const (
|
|
query = `INSERT INTO tab_provider(provider_uuid,provider_internal_id,provider_internal_id_suffix,provider_muk_id,organization_name,gender,accept_new_patients,provider_name,first_name,last_name,middle_name,provider_title,street_name1,street_name2,city_name,state,zipcode,country,latitude,longitude,phone_number,created_user)
|
|
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);`
|
|
)
|
|
|
|
UUID, _ := uuid.NewV4()
|
|
lat, _ := strconv.ParseFloat(provider.Latitude, 64)
|
|
long, _ := strconv.ParseFloat(provider.Longitude, 64)
|
|
|
|
p := entity.Provider{
|
|
ProviderUUID: UUID.String(),
|
|
InternalID: provider.FivePartKeyGroups[0].ProviderNum,
|
|
InternalSuffixID: provider.FivePartKeyGroups[0].ProviderNumSuffix,
|
|
MukID: provider.MukID,
|
|
OrganizatioName: provider.OrgName,
|
|
Gender: provider.Gender,
|
|
AcceptNewPatients: provider.AcceptNewPatients,
|
|
Name: provider.ProviderName,
|
|
FirstName: provider.FirstName,
|
|
MiddleName: provider.MiddleName,
|
|
LastName: provider.LastName,
|
|
Title: provider.ProviderTitle,
|
|
Address: entity.ProviderAddress{
|
|
StreetAddress1: provider.StreetName1,
|
|
StreetAddress2: provider.StreetName2,
|
|
CityName: provider.CityName,
|
|
State: provider.State,
|
|
ZipCode: provider.ZipCode,
|
|
Country: provider.Country,
|
|
Latitude: lat,
|
|
Longitude: long,
|
|
PhoneNumber: provider.PhoneNumber,
|
|
},
|
|
CreateDate: time.Now(),
|
|
UpdateDate: time.Now(),
|
|
Active: true,
|
|
Enabled: true,
|
|
}
|
|
|
|
result, err := c.conn.Exec(query, p.ProviderUUID, p.InternalID, p.InternalSuffixID, p.MukID, p.OrganizatioName, p.Gender, p.AcceptNewPatients, p.Name, p.FirstName, p.LastName, p.MiddleName, p.Title, p.Address.StreetAddress1, p.Address.StreetAddress2, p.Address.CityName, p.Address.State, p.Address.ZipCode, p.Address.Country, p.Address.Latitude, p.Address.Longitude, p.Address.PhoneNumber, 1)
|
|
if err != nil {
|
|
if driverErr, ok := err.(*mysql.MySQLError); ok {
|
|
if driverErr.Number != 1062 {
|
|
return entity.Provider{}, err
|
|
} else {
|
|
tempProvider, err := c.GetByMukID(p.MukID, user)
|
|
if err != nil {
|
|
return entity.Provider{}, err
|
|
}
|
|
p.ProviderID = tempProvider.ProviderID
|
|
}
|
|
}
|
|
} else {
|
|
p.ProviderID, err = result.LastInsertId()
|
|
if err != nil {
|
|
return entity.Provider{}, err
|
|
}
|
|
}
|
|
|
|
var providerKeys []entity.ProviderKey
|
|
for _, fk := range provider.FivePartKeyGroups {
|
|
key, err := c.saveKeys(p.ProviderID, fk)
|
|
if err != nil {
|
|
return p, err
|
|
}
|
|
providerKeys = append(providerKeys, key)
|
|
}
|
|
p.Keys = providerKeys
|
|
|
|
return p, nil
|
|
}
|
|
|
|
func (c *providerRepo) saveKeys(ProviderID int64, fk entity.PartKeyGroup) (entity.ProviderKey, error) {
|
|
const (
|
|
query = `INSERT INTO tab_provider_key (provider_id, internal_id, internal_id_suffix, location_seq_num, plan_code, product_id, treatment_category_code, created_user)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE provider_id = ?, internal_id = ?, internal_id_suffix = ?, location_seq_num = ?, plan_code = ?, product_id = ?, treatment_category_code = ?, created_user = ?;`
|
|
)
|
|
|
|
key := entity.ProviderKey{
|
|
InternalID: fk.ProviderNum,
|
|
InternalSuffixID: fk.ProviderNumSuffix,
|
|
TreatmentCategoryCode: fk.TreatmentCategoryCode,
|
|
ProductID: fk.ProductID,
|
|
PlanCode: fk.PlanCode,
|
|
LocationSeqNumber: fk.LocationSeqNum,
|
|
Provider: entity.Provider{
|
|
ProviderID: ProviderID,
|
|
},
|
|
}
|
|
|
|
result, err := c.conn.Exec(query, key.Provider.ProviderID, key.InternalID, key.InternalSuffixID, key.LocationSeqNumber, key.PlanCode, key.ProductID, key.TreatmentCategoryCode, 1, key.Provider.ProviderID, key.InternalID, key.InternalSuffixID, key.LocationSeqNumber, key.PlanCode, key.ProductID, key.TreatmentCategoryCode, 1)
|
|
if err != nil {
|
|
return key, err
|
|
}
|
|
|
|
key.ProviderKeyID, err = result.LastInsertId()
|
|
if err != nil {
|
|
return key, err
|
|
}
|
|
|
|
return key, nil
|
|
}
|