Merged in feature/textExtractionsPart2 (pull request #193)

Continue finishing the parts of the text extraction plan

* add missing fields
This commit is contained in:
Jay Brown
2025-12-02 19:13:08 +00:00
parent c45e1dd427
commit 3bdc27f4de
21 changed files with 2392 additions and 215 deletions
+241
View File
@@ -141,6 +141,42 @@ func (s *Controllers) GetFieldExtractionHistory(ctx echo.Context, params GetFiel
})
}
// 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{}
@@ -160,6 +196,59 @@ func buildFieldExtractionResponse(current *repository.Currentfieldextraction, ar
}
}
// 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{
@@ -300,12 +389,57 @@ func convertAPIArrayFieldItemToRepo(item *ArrayFieldItem) *repository.AddFieldEx
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)
@@ -317,6 +451,37 @@ func convertAPIArrayFieldItemToRepo(item *ArrayFieldItem) *repository.AddFieldEx
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)
@@ -391,11 +556,56 @@ func convertRepoArrayFieldToAPI(f *repository.Documentfieldextractionarrayfield)
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
@@ -409,6 +619,37 @@ func convertRepoArrayFieldToAPI(f *repository.Documentfieldextractionarrayfield)
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)