3bdc27f4de
Continue finishing the parts of the text extraction plan * add missing fields
703 lines
28 KiB
Go
703 lines
28 KiB
Go
package queryapi
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"queryorchestration/internal/database/repository"
|
|
"queryorchestration/internal/fieldextraction"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"github.com/labstack/echo/v4"
|
|
openapi_types "github.com/oapi-codegen/runtime/types"
|
|
)
|
|
|
|
// CreateFieldExtraction creates a new field extraction with single-value and array fields.
|
|
// This endpoint creates a versioned field extraction record for a document.
|
|
func (s *Controllers) CreateFieldExtraction(ctx echo.Context) error {
|
|
var req FieldExtractionRequest
|
|
if err := ctx.Bind(&req); err != nil {
|
|
slog.Error("failed to parse field extraction request", "error", err)
|
|
return echo.NewHTTPError(http.StatusBadRequest, "invalid request body")
|
|
}
|
|
|
|
// Validate required fields
|
|
documentID := uuid.UUID(req.DocumentId)
|
|
if documentID == uuid.Nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, "documentId is required")
|
|
}
|
|
|
|
createdBy := string(req.CreatedBy)
|
|
if createdBy == "" {
|
|
return echo.NewHTTPError(http.StatusBadRequest, "createdBy is required")
|
|
}
|
|
|
|
// Convert API request to service input
|
|
input := &fieldextraction.CreateFieldExtractionInput{
|
|
DocumentID: documentID,
|
|
SingleFields: convertAPISingleFieldsToRepo(&req.SingleFields, createdBy),
|
|
ArrayFields: convertAPIArrayFieldsToRepo(req.ArrayFields),
|
|
}
|
|
|
|
// Create field extraction via service
|
|
extraction, err := s.svc.FieldExtraction.CreateFieldExtraction(ctx.Request().Context(), input)
|
|
if err != nil {
|
|
slog.Error("failed to create field extraction", "error", err, "document_id", documentID)
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "failed to create field extraction")
|
|
}
|
|
|
|
// Fetch the current extraction to get version info
|
|
current, err := s.svc.FieldExtraction.GetCurrentFieldExtraction(ctx.Request().Context(), documentID)
|
|
if err != nil {
|
|
slog.Error("failed to get current field extraction after creation", "error", err, "document_id", documentID)
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get created field extraction")
|
|
}
|
|
|
|
// Fetch array fields for response
|
|
arrayFields, err := s.svc.FieldExtraction.GetFieldExtractionArrayFields(ctx.Request().Context(), extraction.ID)
|
|
if err != nil {
|
|
slog.Error("failed to get array fields after creation", "error", err, "extraction_id", extraction.ID)
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get array fields")
|
|
}
|
|
|
|
// Build response
|
|
response := buildFieldExtractionResponse(current, arrayFields)
|
|
|
|
return ctx.JSON(http.StatusCreated, response)
|
|
}
|
|
|
|
// GetCurrentFieldExtraction retrieves the most recent field extraction for a document.
|
|
// This returns the current (latest version) field extraction including all single and array fields.
|
|
func (s *Controllers) GetCurrentFieldExtraction(ctx echo.Context, params GetCurrentFieldExtractionParams) error {
|
|
documentID := uuid.UUID(params.DocumentId)
|
|
if documentID == uuid.Nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, "documentId is required")
|
|
}
|
|
|
|
// Get current field extraction
|
|
current, err := s.svc.FieldExtraction.GetCurrentFieldExtraction(ctx.Request().Context(), documentID)
|
|
if err != nil {
|
|
slog.Error("failed to get current field extraction", "error", err, "document_id", documentID)
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get field extraction")
|
|
}
|
|
|
|
if current == nil {
|
|
return echo.NewHTTPError(http.StatusNotFound, "no field extraction found for document")
|
|
}
|
|
|
|
// Fetch array fields
|
|
arrayFields, err := s.svc.FieldExtraction.GetFieldExtractionArrayFields(ctx.Request().Context(), current.ID)
|
|
if err != nil {
|
|
slog.Error("failed to get array fields", "error", err, "extraction_id", current.ID)
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get array fields")
|
|
}
|
|
|
|
// Build response
|
|
response := buildFieldExtractionResponse(current, arrayFields)
|
|
|
|
return ctx.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// GetFieldExtractionHistory retrieves all versions of field extractions for a document.
|
|
// This returns version metadata without the full field data for each version.
|
|
func (s *Controllers) GetFieldExtractionHistory(ctx echo.Context, params GetFieldExtractionHistoryParams) error {
|
|
documentID := uuid.UUID(params.DocumentId)
|
|
if documentID == uuid.Nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, "documentId is required")
|
|
}
|
|
|
|
// Get version history
|
|
history, err := s.svc.FieldExtraction.GetFieldExtractionHistory(ctx.Request().Context(), documentID)
|
|
if err != nil {
|
|
slog.Error("failed to get field extraction history", "error", err, "document_id", documentID)
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get field extraction history")
|
|
}
|
|
|
|
// Convert to API response
|
|
versions := make([]FieldExtractionVersion, len(history))
|
|
for i, h := range history {
|
|
createdAt := time.Time{}
|
|
if h.Createdat.Valid {
|
|
createdAt = h.Createdat.Time
|
|
}
|
|
|
|
versions[i] = FieldExtractionVersion{
|
|
Id: openapi_types.UUID(h.ID),
|
|
DocumentId: DocumentID(h.Documentid),
|
|
//nolint:gosec // Version is a small number, int32 is sufficient
|
|
Version: int32(h.Version), // Already 1-based in database
|
|
CreatedAt: createdAt,
|
|
CreatedBy: openapi_types.Email(h.Createdby),
|
|
}
|
|
}
|
|
|
|
return ctx.JSON(http.StatusOK, struct {
|
|
Versions []FieldExtractionVersion `json:"versions"`
|
|
}{
|
|
Versions: versions,
|
|
})
|
|
}
|
|
|
|
// GetFieldExtractionByVersion retrieves a specific version of field extraction for a document.
|
|
// This endpoint returns the full field extraction data for a specific version.
|
|
func (s *Controllers) GetFieldExtractionByVersion(ctx echo.Context, params GetFieldExtractionByVersionParams) error {
|
|
documentID := uuid.UUID(params.DocumentId)
|
|
if documentID == uuid.Nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, "documentId is required")
|
|
}
|
|
|
|
if params.Version < 1 {
|
|
return echo.NewHTTPError(http.StatusBadRequest, "version must be at least 1")
|
|
}
|
|
|
|
// Get field extraction by version
|
|
extraction, err := s.svc.FieldExtraction.GetFieldExtractionByVersion(ctx.Request().Context(), documentID, params.Version)
|
|
if err != nil {
|
|
slog.Error("failed to get field extraction by version", "error", err, "document_id", documentID, "version", params.Version)
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get field extraction")
|
|
}
|
|
|
|
if extraction == nil {
|
|
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("no field extraction found for document at version %d", params.Version))
|
|
}
|
|
|
|
// Fetch array fields
|
|
arrayFields, err := s.svc.FieldExtraction.GetFieldExtractionArrayFields(ctx.Request().Context(), extraction.ID)
|
|
if err != nil {
|
|
slog.Error("failed to get array fields", "error", err, "extraction_id", extraction.ID)
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get array fields")
|
|
}
|
|
|
|
// Build response
|
|
response := buildFieldExtractionResponseFromVersionRow(extraction, arrayFields)
|
|
|
|
return ctx.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// buildFieldExtractionResponse builds the API response from the repository types
|
|
func buildFieldExtractionResponse(current *repository.Currentfieldextraction, arrayFields []*repository.Documentfieldextractionarrayfield) *FieldExtractionResponse {
|
|
createdAt := time.Time{}
|
|
if current.Createdat.Valid {
|
|
createdAt = current.Createdat.Time
|
|
}
|
|
|
|
return &FieldExtractionResponse{
|
|
Id: openapi_types.UUID(current.ID),
|
|
DocumentId: DocumentID(current.Documentid),
|
|
//nolint:gosec // Version is a small number, int32 is sufficient
|
|
Version: int32(current.Version), // Already 1-based in database
|
|
SingleFields: convertRepoSingleFieldsToAPI(current),
|
|
ArrayFields: convertRepoArrayFieldsToAPI(arrayFields),
|
|
CreatedAt: createdAt,
|
|
CreatedBy: openapi_types.Email(current.Createdby),
|
|
}
|
|
}
|
|
|
|
// buildFieldExtractionResponseFromVersionRow builds the API response from the version-specific repository types
|
|
func buildFieldExtractionResponseFromVersionRow(row *repository.GetFieldExtractionByVersionRow, arrayFields []*repository.Documentfieldextractionarrayfield) *FieldExtractionResponse {
|
|
createdAt := time.Time{}
|
|
if row.Createdat.Valid {
|
|
createdAt = row.Createdat.Time
|
|
}
|
|
|
|
return &FieldExtractionResponse{
|
|
Id: openapi_types.UUID(row.ID),
|
|
DocumentId: DocumentID(row.Documentid),
|
|
//nolint:gosec // Version is a small number, int32 is sufficient
|
|
Version: int32(row.Version), // Already 1-based in database
|
|
SingleFields: convertRepoSingleFieldsToAPIFromVersionRow(row),
|
|
ArrayFields: convertRepoArrayFieldsToAPI(arrayFields),
|
|
CreatedAt: createdAt,
|
|
CreatedBy: openapi_types.Email(row.Createdby),
|
|
}
|
|
}
|
|
|
|
// convertRepoSingleFieldsToAPIFromVersionRow converts repository GetFieldExtractionByVersionRow to API SingleFields
|
|
func convertRepoSingleFieldsToAPIFromVersionRow(row *repository.GetFieldExtractionByVersionRow) SingleFields {
|
|
sf := SingleFields{
|
|
FileName: row.Filename,
|
|
ContractTitle: row.Contracttitle,
|
|
AareteDerivedAmendmentNum: row.Aaretederivedamendmentnum,
|
|
ClientName: row.Clientname,
|
|
PayerName: row.Payername,
|
|
PayerState: row.Payerstate,
|
|
ProviderState: row.Providerstate,
|
|
FilenameTin: row.Filenametin,
|
|
ProvGroupTin: row.Provgrouptin,
|
|
ProvGroupNpi: row.Provgroupnpi,
|
|
ProvGroupNameFull: row.Provgroupnamefull,
|
|
ProvOtherTin: row.Provothertin,
|
|
ProvOtherNpi: row.Provothernpi,
|
|
ProvOtherNameFull: row.Provothernamefull,
|
|
AutoRenewalInd: row.Autorenewalind,
|
|
AutoRenewalTerm: row.Autorenewalterm,
|
|
}
|
|
|
|
// Convert dates
|
|
if row.Aaretederivedeffectivedt.Valid {
|
|
d := pgDateToAPIDate(row.Aaretederivedeffectivedt)
|
|
sf.AareteDerivedEffectiveDt = &d
|
|
}
|
|
if row.Aaretederivedterminationdt.Valid {
|
|
d := pgDateToAPIDate(row.Aaretederivedterminationdt)
|
|
sf.AareteDerivedTerminationDt = &d
|
|
}
|
|
|
|
return sf
|
|
}
|
|
|
|
// convertAPISingleFieldsToRepo converts API SingleFields to repository AddFieldExtractionParams
|
|
func convertAPISingleFieldsToRepo(sf *SingleFields, createdBy string) *repository.AddFieldExtractionParams {
|
|
params := &repository.AddFieldExtractionParams{
|
|
Createdby: createdBy,
|
|
}
|
|
|
|
if sf == nil {
|
|
return params
|
|
}
|
|
|
|
params.Filename = sf.FileName
|
|
params.Contracttitle = sf.ContractTitle
|
|
params.Aaretederivedamendmentnum = sf.AareteDerivedAmendmentNum
|
|
params.Clientname = sf.ClientName
|
|
params.Payername = sf.PayerName
|
|
params.Payerstate = sf.PayerState
|
|
params.Providerstate = sf.ProviderState
|
|
params.Filenametin = sf.FilenameTin
|
|
params.Provgrouptin = sf.ProvGroupTin
|
|
params.Provgroupnpi = sf.ProvGroupNpi
|
|
params.Provgroupnamefull = sf.ProvGroupNameFull
|
|
params.Provothertin = sf.ProvOtherTin
|
|
params.Provothernpi = sf.ProvOtherNpi
|
|
params.Provothernamefull = sf.ProvOtherNameFull
|
|
params.Autorenewalind = sf.AutoRenewalInd
|
|
params.Autorenewalterm = sf.AutoRenewalTerm
|
|
|
|
// Convert dates
|
|
if sf.AareteDerivedEffectiveDt != nil {
|
|
params.Aaretederivedeffectivedt = dateToPgDate(*sf.AareteDerivedEffectiveDt)
|
|
}
|
|
if sf.AareteDerivedTerminationDt != nil {
|
|
params.Aaretederivedterminationdt = dateToPgDate(*sf.AareteDerivedTerminationDt)
|
|
}
|
|
|
|
return params
|
|
}
|
|
|
|
// convertRepoSingleFieldsToAPI converts repository Currentfieldextraction to API SingleFields
|
|
func convertRepoSingleFieldsToAPI(cf *repository.Currentfieldextraction) SingleFields {
|
|
sf := SingleFields{
|
|
FileName: cf.Filename,
|
|
ContractTitle: cf.Contracttitle,
|
|
AareteDerivedAmendmentNum: cf.Aaretederivedamendmentnum,
|
|
ClientName: cf.Clientname,
|
|
PayerName: cf.Payername,
|
|
PayerState: cf.Payerstate,
|
|
ProviderState: cf.Providerstate,
|
|
FilenameTin: cf.Filenametin,
|
|
ProvGroupTin: cf.Provgrouptin,
|
|
ProvGroupNpi: cf.Provgroupnpi,
|
|
ProvGroupNameFull: cf.Provgroupnamefull,
|
|
ProvOtherTin: cf.Provothertin,
|
|
ProvOtherNpi: cf.Provothernpi,
|
|
ProvOtherNameFull: cf.Provothernamefull,
|
|
AutoRenewalInd: cf.Autorenewalind,
|
|
AutoRenewalTerm: cf.Autorenewalterm,
|
|
}
|
|
|
|
// Convert dates
|
|
if cf.Aaretederivedeffectivedt.Valid {
|
|
d := pgDateToAPIDate(cf.Aaretederivedeffectivedt)
|
|
sf.AareteDerivedEffectiveDt = &d
|
|
}
|
|
if cf.Aaretederivedterminationdt.Valid {
|
|
d := pgDateToAPIDate(cf.Aaretederivedterminationdt)
|
|
sf.AareteDerivedTerminationDt = &d
|
|
}
|
|
|
|
return sf
|
|
}
|
|
|
|
// convertAPIArrayFieldsToRepo converts API ArrayFieldItem slice to repository AddFieldExtractionArrayFieldParams slice
|
|
func convertAPIArrayFieldsToRepo(items []ArrayFieldItem) []*repository.AddFieldExtractionArrayFieldParams {
|
|
result := make([]*repository.AddFieldExtractionArrayFieldParams, len(items))
|
|
for i, item := range items {
|
|
result[i] = convertAPIArrayFieldItemToRepo(&item)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// convertAPIArrayFieldItemToRepo converts a single API ArrayFieldItem to repository params
|
|
func convertAPIArrayFieldItemToRepo(item *ArrayFieldItem) *repository.AddFieldExtractionArrayFieldParams {
|
|
params := &repository.AddFieldExtractionArrayFieldParams{}
|
|
|
|
if item == nil {
|
|
return params
|
|
}
|
|
|
|
// String fields
|
|
params.Exhibittitle = item.ExhibitTitle
|
|
params.Exhibitpage = item.ExhibitPage
|
|
params.Reimbprovtin = item.ReimbProvTin
|
|
params.Reimbprovnpi = item.ReimbProvNpi
|
|
params.Reimbprovname = item.ReimbProvName
|
|
params.Aaretederivedclaimtypecd = item.AareteDerivedClaimTypeCd
|
|
params.Aaretederivedproduct = item.AareteDerivedProduct
|
|
params.Aaretederivedlob = item.AareteDerivedLob
|
|
params.Aaretederivedprogram = item.AareteDerivedProgram
|
|
params.Aaretederivednetwork = item.AareteDerivedNetwork
|
|
params.Aaretederivedprovtype = item.AareteDerivedProvType
|
|
params.Provtaxonomycd = item.ProvTaxonomyCd
|
|
params.Provtaxonomycddesc = item.ProvTaxonomyCdDesc
|
|
params.Provspecialtycd = item.ProvSpecialtyCd
|
|
params.Provspecialtycddesc = item.ProvSpecialtyCdDesc
|
|
params.Placeofservicecd = item.PlaceOfServiceCd
|
|
params.Placeofservicecddesc = item.PlaceOfServiceCdDesc
|
|
params.Billtypecd = item.BillTypeCd
|
|
params.Billtypecddesc = item.BillTypeCdDesc
|
|
params.Patientagemin = item.PatientAgeMin
|
|
params.Patientagemax = item.PatientAgeMax
|
|
params.Reimbterm = item.ReimbTerm
|
|
params.Lobprogramrelationship = item.LobProgramRelationship
|
|
params.Lobproductrelationship = item.LobProductRelationship
|
|
params.Aaretederivedreimbmethod = item.AareteDerivedReimbMethod
|
|
params.Unitofmeasure = item.UnitOfMeasure
|
|
params.Additiondesc = item.AdditionDesc
|
|
params.Aaretederivedadditionratechangetimeline = item.AareteDerivedAdditionRateChangeTimeline
|
|
params.Aaretederivedfeeschedule = item.AareteDerivedFeeSchedule
|
|
params.Aaretederivedfeescheduleversion = item.AareteDerivedFeeScheduleVersion
|
|
params.Serviceterm = item.ServiceTerm
|
|
params.Cpt4proccd = item.Cpt4ProcCd
|
|
params.Cpt4proccddesc = item.Cpt4ProcCdDesc
|
|
params.Cpt4procmod = item.Cpt4ProcMod
|
|
params.Cpt4procmoddesc = item.Cpt4ProcModDesc
|
|
params.Revenuecd = item.RevenueCd
|
|
params.Revenuecddesc = item.RevenueCdDesc
|
|
params.Diagcd = item.DiagCd
|
|
params.Diagcddesc = item.DiagCdDesc
|
|
params.Ndccd = item.NdcCd
|
|
params.Ndccddesc = item.NdcCdDesc
|
|
params.Claimadmittypecd = item.ClaimAdmitTypeCd
|
|
params.Authadmittypedesc = item.AuthAdmitTypeDesc
|
|
params.Claimstatuscd = item.ClaimStatusCd
|
|
params.Claimstatuscddesc = item.ClaimStatusCdDesc
|
|
params.Groupertype = item.GrouperType
|
|
params.Groupercd = item.GrouperCd
|
|
params.Groupercddesc = item.GrouperCdDesc
|
|
params.Carveoutcd = item.CarveoutCd
|
|
|
|
// Grouper extended fields
|
|
params.Aaretederivedgrouperversion = item.AareteDerivedGrouperVersion
|
|
params.Grouperalternativelevelofcare = item.GrouperAlternativeLevelOfCare
|
|
params.Grouperseverity = item.GrouperSeverity
|
|
params.Grouperriskofmortalitysubclass = item.GrouperRiskOfMortalitySubclass
|
|
|
|
// Outlier fields
|
|
params.Outlierterm = item.OutlierTerm
|
|
params.Rangenbrdays = item.RangeNbrDays
|
|
params.Outlierexclusioncd = item.OutlierExclusionCd
|
|
params.Outlierexclusioncddesc = item.OutlierExclusionCdDesc
|
|
|
|
// Facility adjustment fields
|
|
params.Facilityadjustmentterm = item.FacilityAdjustmentTerm
|
|
|
|
// Rate escalator fields
|
|
params.Rateescalatordesc = item.RateEscalatorDesc
|
|
|
|
// Stop loss fields
|
|
params.Stoplossterm = item.StopLossTerm
|
|
params.Stoplossexclusioncd = item.StopLossExclusionCd
|
|
params.Stoplossexclusiondesc = item.StopLossExclusionDesc
|
|
|
|
// Boolean fields
|
|
params.Carveoutind = item.CarveoutInd
|
|
params.Lesserofind = item.LesserOfInd
|
|
params.Greaterofind = item.GreaterOfInd
|
|
params.Defaultind = item.DefaultInd
|
|
|
|
// Grouper extended boolean fields
|
|
params.Grouperseverityind = item.GrouperSeverityInd
|
|
params.Groupertransferind = item.GrouperTransferInd
|
|
params.Grouperreadmissionsind = item.GrouperReadmissionsInd
|
|
params.Grouperhacind = item.GrouperHacInd
|
|
|
|
// Outlier boolean fields
|
|
params.Outlierfirstdollarind = item.OutlierFirstDollarInd
|
|
|
|
// Facility adjustment boolean fields
|
|
params.Dshind = item.DshInd
|
|
params.Imeind = item.ImeInd
|
|
params.Ntapind = item.NtapInd
|
|
params.Ucind = item.UcInd
|
|
params.Gmeind = item.GmeInd
|
|
|
|
// Rate escalator boolean fields
|
|
params.Rateescalatorind = item.RateEscalatorInd
|
|
|
|
// Stop loss boolean fields
|
|
params.Stoplossfirstdollarind = item.StopLossFirstDollarInd
|
|
|
|
// Numeric fields
|
|
params.Reimbpctrate = float64ToPgNumeric(item.ReimbPctRate)
|
|
params.Reimbfeerate = float64ToPgNumeric(item.ReimbFeeRate)
|
|
params.Reimbconversionfactor = float64ToPgNumeric(item.ReimbConversionFactor)
|
|
params.Triggercapthresholdamt = float64ToPgNumeric(item.TriggerCapThresholdAmt)
|
|
params.Triggerbasethreshold = float64ToPgNumeric(item.TriggerBaseThreshold)
|
|
params.Additionmaxfeerateinc = float64ToPgNumeric(item.AdditionMaxFeeRateInc)
|
|
params.Additionmaxpctrateinc = float64ToPgNumeric(item.AdditionMaxPctRateInc)
|
|
params.Grouperpctrate = float64ToPgNumeric(item.GrouperPctRate)
|
|
params.Grouperbaserate = float64ToPgNumeric(item.GrouperBaseRate)
|
|
|
|
// Outlier numeric fields
|
|
params.Outlierfixedlossnbrdaysthreshold = float64ToPgNumeric(item.OutlierFixedLossNbrDaysThreshold)
|
|
params.Outlierfixedlossthreshold = float64ToPgNumeric(item.OutlierFixedLossThreshold)
|
|
params.Outliermaximum = float64ToPgNumeric(item.OutlierMaximum)
|
|
params.Outliermaximumfrequency = float64ToPgNumeric(item.OutlierMaximumFrequency)
|
|
params.Outlierpctrate = float64ToPgNumeric(item.OutlierPctRate)
|
|
|
|
// Facility adjustment numeric fields
|
|
params.Dshpctrate = float64ToPgNumeric(item.DshPctRate)
|
|
params.Dshfeerate = float64ToPgNumeric(item.DshFeeRate)
|
|
params.Imepctrate = float64ToPgNumeric(item.ImePctRate)
|
|
params.Imefeerate = float64ToPgNumeric(item.ImeFeeRate)
|
|
params.Ntappctrate = float64ToPgNumeric(item.NtapPctRate)
|
|
params.Ntapfeerate = float64ToPgNumeric(item.NtapFeeRate)
|
|
params.Ucpctrate = float64ToPgNumeric(item.UcPctRate)
|
|
params.Ucfeerate = float64ToPgNumeric(item.UcFeeRate)
|
|
params.Gmepctrate = float64ToPgNumeric(item.GmePctRate)
|
|
params.Gmefeerate = float64ToPgNumeric(item.GmeFeeRate)
|
|
|
|
// Rate escalator numeric fields
|
|
params.Rateescalatormaxrateincpct = float64ToPgNumeric(item.RateEscalatorMaxRateIncPct)
|
|
params.Rateescalatorratechangetimeline = float64ToPgNumeric(item.RateEscalatorRateChangeTimeline)
|
|
|
|
// Stop loss numeric fields
|
|
params.Stoplossrangenbrdays = float64ToPgNumeric(item.StopLossRangeNbrDays)
|
|
params.Stoplossfixedlossthreshold = float64ToPgNumeric(item.StopLossFixedLossThreshold)
|
|
params.Stoplossmaximum = float64ToPgNumeric(item.StopLossMaximum)
|
|
params.Stoplossmaximumfrequency = float64ToPgNumeric(item.StopLossMaximumFrequency)
|
|
params.Stoplossdailymaxrate = float64ToPgNumeric(item.StopLossDailyMaxRate)
|
|
params.Stoplosspctrateonexcesscharges = float64ToPgNumeric(item.StopLossPctRateOnExcessCharges)
|
|
|
|
// Date fields
|
|
if item.ReimbEffectiveDt != nil {
|
|
params.Reimbeffectivedt = dateToPgDate(*item.ReimbEffectiveDt)
|
|
}
|
|
if item.ReimbTerminationDt != nil {
|
|
params.Reimbterminationdt = dateToPgDate(*item.ReimbTerminationDt)
|
|
}
|
|
|
|
return params
|
|
}
|
|
|
|
// convertRepoArrayFieldsToAPI converts repository array fields to API ArrayFieldItem slice
|
|
func convertRepoArrayFieldsToAPI(fields []*repository.Documentfieldextractionarrayfield) []ArrayFieldItem {
|
|
result := make([]ArrayFieldItem, len(fields))
|
|
for i, f := range fields {
|
|
result[i] = convertRepoArrayFieldToAPI(f)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// convertRepoArrayFieldToAPI converts a single repository array field to API ArrayFieldItem
|
|
func convertRepoArrayFieldToAPI(f *repository.Documentfieldextractionarrayfield) ArrayFieldItem {
|
|
item := ArrayFieldItem{
|
|
// String fields
|
|
ExhibitTitle: f.Exhibittitle,
|
|
ExhibitPage: f.Exhibitpage,
|
|
ReimbProvTin: f.Reimbprovtin,
|
|
ReimbProvNpi: f.Reimbprovnpi,
|
|
ReimbProvName: f.Reimbprovname,
|
|
AareteDerivedClaimTypeCd: f.Aaretederivedclaimtypecd,
|
|
AareteDerivedProduct: f.Aaretederivedproduct,
|
|
AareteDerivedLob: f.Aaretederivedlob,
|
|
AareteDerivedProgram: f.Aaretederivedprogram,
|
|
AareteDerivedNetwork: f.Aaretederivednetwork,
|
|
AareteDerivedProvType: f.Aaretederivedprovtype,
|
|
ProvTaxonomyCd: f.Provtaxonomycd,
|
|
ProvTaxonomyCdDesc: f.Provtaxonomycddesc,
|
|
ProvSpecialtyCd: f.Provspecialtycd,
|
|
ProvSpecialtyCdDesc: f.Provspecialtycddesc,
|
|
PlaceOfServiceCd: f.Placeofservicecd,
|
|
PlaceOfServiceCdDesc: f.Placeofservicecddesc,
|
|
BillTypeCd: f.Billtypecd,
|
|
BillTypeCdDesc: f.Billtypecddesc,
|
|
PatientAgeMin: f.Patientagemin,
|
|
PatientAgeMax: f.Patientagemax,
|
|
ReimbTerm: f.Reimbterm,
|
|
LobProgramRelationship: f.Lobprogramrelationship,
|
|
LobProductRelationship: f.Lobproductrelationship,
|
|
AareteDerivedReimbMethod: f.Aaretederivedreimbmethod,
|
|
UnitOfMeasure: f.Unitofmeasure,
|
|
AdditionDesc: f.Additiondesc,
|
|
AareteDerivedAdditionRateChangeTimeline: f.Aaretederivedadditionratechangetimeline,
|
|
AareteDerivedFeeSchedule: f.Aaretederivedfeeschedule,
|
|
AareteDerivedFeeScheduleVersion: f.Aaretederivedfeescheduleversion,
|
|
ServiceTerm: f.Serviceterm,
|
|
Cpt4ProcCd: f.Cpt4proccd,
|
|
Cpt4ProcCdDesc: f.Cpt4proccddesc,
|
|
Cpt4ProcMod: f.Cpt4procmod,
|
|
Cpt4ProcModDesc: f.Cpt4procmoddesc,
|
|
RevenueCd: f.Revenuecd,
|
|
RevenueCdDesc: f.Revenuecddesc,
|
|
DiagCd: f.Diagcd,
|
|
DiagCdDesc: f.Diagcddesc,
|
|
NdcCd: f.Ndccd,
|
|
NdcCdDesc: f.Ndccddesc,
|
|
ClaimAdmitTypeCd: f.Claimadmittypecd,
|
|
AuthAdmitTypeDesc: f.Authadmittypedesc,
|
|
ClaimStatusCd: f.Claimstatuscd,
|
|
ClaimStatusCdDesc: f.Claimstatuscddesc,
|
|
GrouperType: f.Groupertype,
|
|
GrouperCd: f.Groupercd,
|
|
GrouperCdDesc: f.Groupercddesc,
|
|
CarveoutCd: f.Carveoutcd,
|
|
|
|
// Grouper extended string fields
|
|
AareteDerivedGrouperVersion: f.Aaretederivedgrouperversion,
|
|
GrouperAlternativeLevelOfCare: f.Grouperalternativelevelofcare,
|
|
GrouperSeverity: f.Grouperseverity,
|
|
GrouperRiskOfMortalitySubclass: f.Grouperriskofmortalitysubclass,
|
|
|
|
// Outlier string fields
|
|
OutlierTerm: f.Outlierterm,
|
|
RangeNbrDays: f.Rangenbrdays,
|
|
OutlierExclusionCd: f.Outlierexclusioncd,
|
|
OutlierExclusionCdDesc: f.Outlierexclusioncddesc,
|
|
|
|
// Facility adjustment string fields
|
|
FacilityAdjustmentTerm: f.Facilityadjustmentterm,
|
|
|
|
// Rate escalator string fields
|
|
RateEscalatorDesc: f.Rateescalatordesc,
|
|
|
|
// Stop loss string fields
|
|
StopLossTerm: f.Stoplossterm,
|
|
StopLossExclusionCd: f.Stoplossexclusioncd,
|
|
StopLossExclusionDesc: f.Stoplossexclusiondesc,
|
|
|
|
// Boolean fields
|
|
CarveoutInd: f.Carveoutind,
|
|
LesserOfInd: f.Lesserofind,
|
|
GreaterOfInd: f.Greaterofind,
|
|
DefaultInd: f.Defaultind,
|
|
|
|
// Grouper extended boolean fields
|
|
GrouperSeverityInd: f.Grouperseverityind,
|
|
GrouperTransferInd: f.Groupertransferind,
|
|
GrouperReadmissionsInd: f.Grouperreadmissionsind,
|
|
GrouperHacInd: f.Grouperhacind,
|
|
|
|
// Outlier boolean fields
|
|
OutlierFirstDollarInd: f.Outlierfirstdollarind,
|
|
|
|
// Facility adjustment boolean fields
|
|
DshInd: f.Dshind,
|
|
ImeInd: f.Imeind,
|
|
NtapInd: f.Ntapind,
|
|
UcInd: f.Ucind,
|
|
GmeInd: f.Gmeind,
|
|
|
|
// Rate escalator boolean fields
|
|
RateEscalatorInd: f.Rateescalatorind,
|
|
|
|
// Stop loss boolean fields
|
|
StopLossFirstDollarInd: f.Stoplossfirstdollarind,
|
|
}
|
|
|
|
// Numeric fields
|
|
item.ReimbPctRate = pgNumericToFloat64(f.Reimbpctrate)
|
|
item.ReimbFeeRate = pgNumericToFloat64(f.Reimbfeerate)
|
|
item.ReimbConversionFactor = pgNumericToFloat64(f.Reimbconversionfactor)
|
|
item.TriggerCapThresholdAmt = pgNumericToFloat64(f.Triggercapthresholdamt)
|
|
item.TriggerBaseThreshold = pgNumericToFloat64(f.Triggerbasethreshold)
|
|
item.AdditionMaxFeeRateInc = pgNumericToFloat64(f.Additionmaxfeerateinc)
|
|
item.AdditionMaxPctRateInc = pgNumericToFloat64(f.Additionmaxpctrateinc)
|
|
item.GrouperPctRate = pgNumericToFloat64(f.Grouperpctrate)
|
|
item.GrouperBaseRate = pgNumericToFloat64(f.Grouperbaserate)
|
|
|
|
// Outlier numeric fields
|
|
item.OutlierFixedLossNbrDaysThreshold = pgNumericToFloat64(f.Outlierfixedlossnbrdaysthreshold)
|
|
item.OutlierFixedLossThreshold = pgNumericToFloat64(f.Outlierfixedlossthreshold)
|
|
item.OutlierMaximum = pgNumericToFloat64(f.Outliermaximum)
|
|
item.OutlierMaximumFrequency = pgNumericToFloat64(f.Outliermaximumfrequency)
|
|
item.OutlierPctRate = pgNumericToFloat64(f.Outlierpctrate)
|
|
|
|
// Facility adjustment numeric fields
|
|
item.DshPctRate = pgNumericToFloat64(f.Dshpctrate)
|
|
item.DshFeeRate = pgNumericToFloat64(f.Dshfeerate)
|
|
item.ImePctRate = pgNumericToFloat64(f.Imepctrate)
|
|
item.ImeFeeRate = pgNumericToFloat64(f.Imefeerate)
|
|
item.NtapPctRate = pgNumericToFloat64(f.Ntappctrate)
|
|
item.NtapFeeRate = pgNumericToFloat64(f.Ntapfeerate)
|
|
item.UcPctRate = pgNumericToFloat64(f.Ucpctrate)
|
|
item.UcFeeRate = pgNumericToFloat64(f.Ucfeerate)
|
|
item.GmePctRate = pgNumericToFloat64(f.Gmepctrate)
|
|
item.GmeFeeRate = pgNumericToFloat64(f.Gmefeerate)
|
|
|
|
// Rate escalator numeric fields
|
|
item.RateEscalatorMaxRateIncPct = pgNumericToFloat64(f.Rateescalatormaxrateincpct)
|
|
item.RateEscalatorRateChangeTimeline = pgNumericToFloat64(f.Rateescalatorratechangetimeline)
|
|
|
|
// Stop loss numeric fields
|
|
item.StopLossRangeNbrDays = pgNumericToFloat64(f.Stoplossrangenbrdays)
|
|
item.StopLossFixedLossThreshold = pgNumericToFloat64(f.Stoplossfixedlossthreshold)
|
|
item.StopLossMaximum = pgNumericToFloat64(f.Stoplossmaximum)
|
|
item.StopLossMaximumFrequency = pgNumericToFloat64(f.Stoplossmaximumfrequency)
|
|
item.StopLossDailyMaxRate = pgNumericToFloat64(f.Stoplossdailymaxrate)
|
|
item.StopLossPctRateOnExcessCharges = pgNumericToFloat64(f.Stoplosspctrateonexcesscharges)
|
|
|
|
// Date fields
|
|
if f.Reimbeffectivedt.Valid {
|
|
d := pgDateToAPIDate(f.Reimbeffectivedt)
|
|
item.ReimbEffectiveDt = &d
|
|
}
|
|
if f.Reimbterminationdt.Valid {
|
|
d := pgDateToAPIDate(f.Reimbterminationdt)
|
|
item.ReimbTerminationDt = &d
|
|
}
|
|
|
|
return item
|
|
}
|
|
|
|
// dateToPgDate converts openapi_types.Date to pgtype.Date
|
|
func dateToPgDate(d openapi_types.Date) pgtype.Date {
|
|
return pgtype.Date{
|
|
Time: d.Time,
|
|
Valid: true,
|
|
}
|
|
}
|
|
|
|
// pgDateToAPIDate converts pgtype.Date to openapi_types.Date
|
|
func pgDateToAPIDate(d pgtype.Date) openapi_types.Date {
|
|
return openapi_types.Date{
|
|
Time: d.Time,
|
|
}
|
|
}
|
|
|
|
// float64ToPgNumeric converts *float64 to pgtype.Numeric
|
|
func float64ToPgNumeric(f *float64) pgtype.Numeric {
|
|
if f == nil {
|
|
return pgtype.Numeric{}
|
|
}
|
|
var num pgtype.Numeric
|
|
// Scan doesn't accept float64 directly, need to convert to string
|
|
_ = num.Scan(fmt.Sprintf("%v", *f))
|
|
return num
|
|
}
|
|
|
|
// pgNumericToFloat64 converts pgtype.Numeric to *float64
|
|
func pgNumericToFloat64(n pgtype.Numeric) *float64 {
|
|
if !n.Valid {
|
|
return nil
|
|
}
|
|
f, err := n.Float64Value()
|
|
if err != nil || !f.Valid {
|
|
return nil
|
|
}
|
|
return &f.Float64
|
|
}
|