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
+321 -199
View File
@@ -248,6 +248,7 @@ type ArrayFieldItem struct {
AareteDerivedClaimTypeCd *string `json:"aareteDerivedClaimTypeCd,omitempty"`
AareteDerivedFeeSchedule *string `json:"aareteDerivedFeeSchedule,omitempty"`
AareteDerivedFeeScheduleVersion *string `json:"aareteDerivedFeeScheduleVersion,omitempty"`
AareteDerivedGrouperVersion *string `json:"aareteDerivedGrouperVersion,omitempty"`
AareteDerivedLob *string `json:"aareteDerivedLob,omitempty"`
AareteDerivedNetwork *string `json:"aareteDerivedNetwork,omitempty"`
AareteDerivedProduct *string `json:"aareteDerivedProduct,omitempty"`
@@ -272,19 +273,48 @@ type ArrayFieldItem struct {
DefaultInd *bool `json:"defaultInd,omitempty"`
DiagCd *string `json:"diagCd,omitempty"`
DiagCdDesc *string `json:"diagCdDesc,omitempty"`
DshFeeRate *float64 `json:"dshFeeRate,omitempty"`
DshInd *bool `json:"dshInd,omitempty"`
DshPctRate *float64 `json:"dshPctRate,omitempty"`
ExhibitPage *string `json:"exhibitPage,omitempty"`
ExhibitTitle *string `json:"exhibitTitle,omitempty"`
FacilityAdjustmentTerm *string `json:"facilityAdjustmentTerm,omitempty"`
GmeFeeRate *float64 `json:"gmeFeeRate,omitempty"`
GmeInd *bool `json:"gmeInd,omitempty"`
GmePctRate *float64 `json:"gmePctRate,omitempty"`
GreaterOfInd *bool `json:"greaterOfInd,omitempty"`
GrouperAlternativeLevelOfCare *string `json:"grouperAlternativeLevelOfCare,omitempty"`
GrouperBaseRate *float64 `json:"grouperBaseRate,omitempty"`
GrouperCd *string `json:"grouperCd,omitempty"`
GrouperCdDesc *string `json:"grouperCdDesc,omitempty"`
GrouperHacInd *bool `json:"grouperHacInd,omitempty"`
GrouperPctRate *float64 `json:"grouperPctRate,omitempty"`
GrouperReadmissionsInd *bool `json:"grouperReadmissionsInd,omitempty"`
GrouperRiskOfMortalitySubclass *string `json:"grouperRiskOfMortalitySubclass,omitempty"`
GrouperSeverity *string `json:"grouperSeverity,omitempty"`
GrouperSeverityInd *bool `json:"grouperSeverityInd,omitempty"`
GrouperTransferInd *bool `json:"grouperTransferInd,omitempty"`
GrouperType *string `json:"grouperType,omitempty"`
ImeFeeRate *float64 `json:"imeFeeRate,omitempty"`
ImeInd *bool `json:"imeInd,omitempty"`
ImePctRate *float64 `json:"imePctRate,omitempty"`
LesserOfInd *bool `json:"lesserOfInd,omitempty"`
LobProductRelationship *string `json:"lobProductRelationship,omitempty"`
LobProgramRelationship *string `json:"lobProgramRelationship,omitempty"`
NdcCd *string `json:"ndcCd,omitempty"`
NdcCdDesc *string `json:"ndcCdDesc,omitempty"`
NtapFeeRate *float64 `json:"ntapFeeRate,omitempty"`
NtapInd *bool `json:"ntapInd,omitempty"`
NtapPctRate *float64 `json:"ntapPctRate,omitempty"`
OutlierExclusionCd *string `json:"outlierExclusionCd,omitempty"`
OutlierExclusionCdDesc *string `json:"outlierExclusionCdDesc,omitempty"`
OutlierFirstDollarInd *bool `json:"outlierFirstDollarInd,omitempty"`
OutlierFixedLossNbrDaysThreshold *float64 `json:"outlierFixedLossNbrDaysThreshold,omitempty"`
OutlierFixedLossThreshold *float64 `json:"outlierFixedLossThreshold,omitempty"`
OutlierMaximum *float64 `json:"outlierMaximum,omitempty"`
OutlierMaximumFrequency *float64 `json:"outlierMaximumFrequency,omitempty"`
OutlierPctRate *float64 `json:"outlierPctRate,omitempty"`
OutlierTerm *string `json:"outlierTerm,omitempty"`
PatientAgeMax *string `json:"patientAgeMax,omitempty"`
PatientAgeMin *string `json:"patientAgeMin,omitempty"`
PlaceOfServiceCd *string `json:"placeOfServiceCd,omitempty"`
@@ -293,6 +323,11 @@ type ArrayFieldItem struct {
ProvSpecialtyCdDesc *string `json:"provSpecialtyCdDesc,omitempty"`
ProvTaxonomyCd *string `json:"provTaxonomyCd,omitempty"`
ProvTaxonomyCdDesc *string `json:"provTaxonomyCdDesc,omitempty"`
RangeNbrDays *string `json:"rangeNbrDays,omitempty"`
RateEscalatorDesc *string `json:"rateEscalatorDesc,omitempty"`
RateEscalatorInd *bool `json:"rateEscalatorInd,omitempty"`
RateEscalatorMaxRateIncPct *float64 `json:"rateEscalatorMaxRateIncPct,omitempty"`
RateEscalatorRateChangeTimeline *float64 `json:"rateEscalatorRateChangeTimeline,omitempty"`
ReimbConversionFactor *float64 `json:"reimbConversionFactor,omitempty"`
ReimbEffectiveDt *openapi_types.Date `json:"reimbEffectiveDt,omitempty"`
ReimbFeeRate *float64 `json:"reimbFeeRate,omitempty"`
@@ -305,8 +340,21 @@ type ArrayFieldItem struct {
RevenueCd *string `json:"revenueCd,omitempty"`
RevenueCdDesc *string `json:"revenueCdDesc,omitempty"`
ServiceTerm *string `json:"serviceTerm,omitempty"`
StopLossDailyMaxRate *float64 `json:"stopLossDailyMaxRate,omitempty"`
StopLossExclusionCd *string `json:"stopLossExclusionCd,omitempty"`
StopLossExclusionDesc *string `json:"stopLossExclusionDesc,omitempty"`
StopLossFirstDollarInd *bool `json:"stopLossFirstDollarInd,omitempty"`
StopLossFixedLossThreshold *float64 `json:"stopLossFixedLossThreshold,omitempty"`
StopLossMaximum *float64 `json:"stopLossMaximum,omitempty"`
StopLossMaximumFrequency *float64 `json:"stopLossMaximumFrequency,omitempty"`
StopLossPctRateOnExcessCharges *float64 `json:"stopLossPctRateOnExcessCharges,omitempty"`
StopLossRangeNbrDays *float64 `json:"stopLossRangeNbrDays,omitempty"`
StopLossTerm *string `json:"stopLossTerm,omitempty"`
TriggerBaseThreshold *float64 `json:"triggerBaseThreshold,omitempty"`
TriggerCapThresholdAmt *float64 `json:"triggerCapThresholdAmt,omitempty"`
UcFeeRate *float64 `json:"ucFeeRate,omitempty"`
UcInd *bool `json:"ucInd,omitempty"`
UcPctRate *float64 `json:"ucPctRate,omitempty"`
UnitOfMeasure *string `json:"unitOfMeasure,omitempty"`
}
@@ -432,6 +480,15 @@ type ClientIDBody struct {
Id ClientID `json:"id"`
}
// ClientListResponse Response containing a list of all clients.
type ClientListResponse struct {
// Clients List of clients in the system.
Clients []DocClient `json:"clients"`
// TotalCount Total number of clients.
TotalCount int32 `json:"totalCount"`
}
// ClientName The client name
type ClientName = string
@@ -995,6 +1052,15 @@ type GetFieldExtractionHistoryParams struct {
DocumentId openapi_types.UUID `form:"documentId" json:"documentId"`
}
// GetFieldExtractionByVersionParams defines parameters for GetFieldExtractionByVersion.
type GetFieldExtractionByVersionParams struct {
// DocumentId The document ID
DocumentId openapi_types.UUID `form:"documentId" json:"documentId"`
// Version The version number to retrieve
Version int64 `form:"version" json:"version"`
}
// GetDocumentsByLabelParams defines parameters for GetDocumentsByLabel.
type GetDocumentsByLabelParams struct {
// ClientId The client ID to filter documents
@@ -1123,6 +1189,9 @@ type ServerInterface interface {
// Get client sync status
// (GET /client/{id}/status)
GetStatusByClientId(ctx echo.Context, id ClientID) error
// List all clients
// (GET /clients)
ListClients(ctx echo.Context) error
// Get document details by its id
// (GET /document/{id})
GetDocument(ctx echo.Context, id DocumentID) error
@@ -1144,6 +1213,9 @@ type ServerInterface interface {
// Get field extraction version history
// (GET /field-extractions/history)
GetFieldExtractionHistory(ctx echo.Context, params GetFieldExtractionHistoryParams) error
// Get field extraction by version
// (GET /field-extractions/version)
GetFieldExtractionByVersion(ctx echo.Context, params GetFieldExtractionByVersionParams) error
// Create a new folder
// (POST /folders)
CreateFolder(ctx echo.Context) error
@@ -1653,6 +1725,17 @@ func (w *ServerInterfaceWrapper) GetStatusByClientId(ctx echo.Context) error {
return err
}
// ListClients converts echo context to params.
func (w *ServerInterfaceWrapper) ListClients(ctx echo.Context) error {
var err error
ctx.Set(JwtAuthScopes, []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.ListClients(ctx)
return err
}
// GetDocument converts echo context to params.
func (w *ServerInterfaceWrapper) GetDocument(ctx echo.Context) error {
var err error
@@ -1776,6 +1859,33 @@ func (w *ServerInterfaceWrapper) GetFieldExtractionHistory(ctx echo.Context) err
return err
}
// GetFieldExtractionByVersion converts echo context to params.
func (w *ServerInterfaceWrapper) GetFieldExtractionByVersion(ctx echo.Context) error {
var err error
ctx.Set(JwtAuthScopes, []string{})
// Parameter object where we will unmarshal all parameters from the context
var params GetFieldExtractionByVersionParams
// ------------- Required query parameter "documentId" -------------
err = runtime.BindQueryParameter("form", true, true, "documentId", ctx.QueryParams(), &params.DocumentId)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter documentId: %s", err))
}
// ------------- Required query parameter "version" -------------
err = runtime.BindQueryParameter("form", true, true, "version", ctx.QueryParams(), &params.Version)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter version: %s", err))
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetFieldExtractionByVersion(ctx, params)
return err
}
// CreateFolder converts echo context to params.
func (w *ServerInterfaceWrapper) CreateFolder(ctx echo.Context) error {
var err error
@@ -2052,6 +2162,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
router.POST(baseURL+"/client/:id/export", wrapper.TriggerExport)
router.GET(baseURL+"/client/:id/folders", wrapper.ListClientFolders)
router.GET(baseURL+"/client/:id/status", wrapper.GetStatusByClientId)
router.GET(baseURL+"/clients", wrapper.ListClients)
router.GET(baseURL+"/document/:id", wrapper.GetDocument)
router.GET(baseURL+"/documents/:documentId/labels", wrapper.GetDocumentLabels)
router.POST(baseURL+"/documents/:documentId/labels", wrapper.ApplyLabel)
@@ -2059,6 +2170,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
router.GET(baseURL+"/field-extractions", wrapper.GetCurrentFieldExtraction)
router.POST(baseURL+"/field-extractions", wrapper.CreateFieldExtraction)
router.GET(baseURL+"/field-extractions/history", wrapper.GetFieldExtractionHistory)
router.GET(baseURL+"/field-extractions/version", wrapper.GetFieldExtractionByVersion)
router.POST(baseURL+"/folders", wrapper.CreateFolder)
router.PATCH(baseURL+"/folders/:folderId", wrapper.RenameFolder)
router.GET(baseURL+"/folders/:folderId/documents", wrapper.GetFolderDocuments)
@@ -2079,205 +2191,215 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"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",
"mArJi+O7lcm/fvj6/wIAAP//vFXFz1tGAQA=",
}
// GetSwagger returns the content of the embedded swagger specification file
+24
View File
@@ -58,3 +58,27 @@ func (s *Controllers) UpdateClient(ctx echo.Context, id ClientID) error {
return ctx.NoContent(http.StatusOK)
}
// ListClients returns all clients in the system.
func (s *Controllers) ListClients(ctx echo.Context) error {
clients, err := s.svc.Client.List(ctx.Request().Context())
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Unable to list clients: %s", err))
}
// Convert to API response format
apiClients := make([]DocClient, len(clients))
for i, c := range clients {
apiClients[i] = DocClient{
Id: c.ID,
Name: c.Name,
CanSync: c.CanSync,
}
}
return ctx.JSON(http.StatusOK, ClientListResponse{
Clients: apiClients,
//nolint:gosec // Client count is bounded by maxItems: 10000 in OpenAPI spec
TotalCount: int32(len(apiClients)),
})
}
+73
View File
@@ -111,6 +111,79 @@ func TestUpdateClient(t *testing.T) {
assert.Equal(t, "new_name", client.Name)
}
func TestListClients(t *testing.T) {
cfg := &ControllerConfig{}
test.CreateDB(t, cfg)
initializeTestConfig(t, cfg)
svc := createControllerServices(cfg)
cons := queryapi.NewControllers(svc, cfg)
// Create multiple clients
clients := []struct {
id string
name string
}{
{"client_a", "Alpha Client"},
{"client_b", "Beta Client"},
{"client_c", "Charlie Client"},
}
for _, c := range clients {
err := cfg.GetDBQueries().CreateClient(t.Context(), &repository.CreateClientParams{
Clientid: c.id,
Name: c.name,
})
require.NoError(t, err)
err = cfg.GetDBQueries().AddClientCanSync(t.Context(), &repository.AddClientCanSyncParams{
Clientid: c.id,
Cansync: true,
})
require.NoError(t, err)
}
ctx, rec := createContext(t)
err := cons.ListClients(ctx)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
var response queryapi.ClientListResponse
err = json.Unmarshal(rec.Body.Bytes(), &response)
require.NoError(t, err)
// Verify response
assert.Equal(t, int32(3), response.TotalCount)
assert.Len(t, response.Clients, 3)
// Verify clients are ordered by name (Alpha, Beta, Charlie)
assert.Equal(t, "Alpha Client", response.Clients[0].Name)
assert.Equal(t, "Beta Client", response.Clients[1].Name)
assert.Equal(t, "Charlie Client", response.Clients[2].Name)
}
func TestListClientsEmpty(t *testing.T) {
cfg := &ControllerConfig{}
test.CreateDB(t, cfg)
initializeTestConfig(t, cfg)
svc := createControllerServices(cfg)
cons := queryapi.NewControllers(svc, cfg)
ctx, rec := createContext(t)
err := cons.ListClients(ctx)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
var response queryapi.ClientListResponse
err = json.Unmarshal(rec.Body.Bytes(), &response)
require.NoError(t, err)
assert.Equal(t, int32(0), response.TotalCount)
assert.Empty(t, response.Clients)
}
func initializeTestConfig(t testing.TB, cfg *ControllerConfig) {
// Reset the singleton config state for testing
serviceconfig.ResetConfigInitOnceTestOnly()
+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)
+187
View File
@@ -16,6 +16,7 @@ import (
"queryorchestration/internal/test"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4"
openapi_types "github.com/oapi-codegen/runtime/types"
"github.com/stretchr/testify/assert"
@@ -639,6 +640,192 @@ func TestCreateFieldExtraction_VersionIncrement(t *testing.T) {
assert.Equal(t, "Version 2", *currentResp.SingleFields.ContractTitle)
}
func TestGetFieldExtractionByVersion_Success(t *testing.T) {
ctrl, cfg, documentID, _ := setupFieldExtractionsTestController(t)
ctx := t.Context()
// Create multiple versions with dates for coverage
svc := fieldextraction.New(cfg)
filename := "test.pdf"
for i := 1; i <= 3; i++ {
contractTitle := fmt.Sprintf("Contract Version %d", i)
clientName := fmt.Sprintf("Client %d", i)
// Include dates to test date conversion coverage
effectiveDate := pgtype.Date{Time: time.Date(2024, 1, i, 0, 0, 0, 0, time.UTC), Valid: true}
terminationDate := pgtype.Date{Time: time.Date(2024, 12, i, 0, 0, 0, 0, time.UTC), Valid: true}
_, err := svc.CreateFieldExtraction(ctx, &fieldextraction.CreateFieldExtractionInput{
DocumentID: documentID,
SingleFields: &repository.AddFieldExtractionParams{
Documentid: documentID,
Filename: &filename,
Contracttitle: &contractTitle,
Clientname: &clientName,
Aaretederivedeffectivedt: effectiveDate,
Aaretederivedterminationdt: terminationDate,
Createdby: fmt.Sprintf("user%d@example.com", i),
},
ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{
{
Exhibittitle: ptr(fmt.Sprintf("Exhibit V%d", i)),
},
},
})
require.NoError(t, err)
}
// Test retrieving version 2
e := echo.New()
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=2", documentID), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
params := queryapi.GetFieldExtractionByVersionParams{
DocumentId: queryapi.DocumentID(documentID),
Version: 2,
}
err := ctrl.GetFieldExtractionByVersion(c, params)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
// Parse response
var resp queryapi.FieldExtractionResponse
err = json.Unmarshal(rec.Body.Bytes(), &resp)
require.NoError(t, err)
// Verify we got version 2
assert.Equal(t, documentID, uuid.UUID(resp.DocumentId))
assert.Equal(t, int32(2), resp.Version)
assert.Equal(t, "user2@example.com", string(resp.CreatedBy))
assert.Equal(t, "Contract Version 2", *resp.SingleFields.ContractTitle)
assert.Equal(t, "Client 2", *resp.SingleFields.ClientName)
// Verify dates are returned correctly
require.NotNil(t, resp.SingleFields.AareteDerivedEffectiveDt, "Expected effective date in response")
require.NotNil(t, resp.SingleFields.AareteDerivedTerminationDt, "Expected termination date in response")
assert.Equal(t, 2024, resp.SingleFields.AareteDerivedEffectiveDt.Year())
assert.Equal(t, time.January, resp.SingleFields.AareteDerivedEffectiveDt.Month())
assert.Equal(t, 2, resp.SingleFields.AareteDerivedEffectiveDt.Day())
require.Len(t, resp.ArrayFields, 1)
assert.Equal(t, "Exhibit V2", *resp.ArrayFields[0].ExhibitTitle)
// Also test retrieving version 1
req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=1", documentID), nil)
rec = httptest.NewRecorder()
c = e.NewContext(req, rec)
params.Version = 1
err = ctrl.GetFieldExtractionByVersion(c, params)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
err = json.Unmarshal(rec.Body.Bytes(), &resp)
require.NoError(t, err)
assert.Equal(t, int32(1), resp.Version)
assert.Equal(t, "Contract Version 1", *resp.SingleFields.ContractTitle)
assert.Equal(t, "Exhibit V1", *resp.ArrayFields[0].ExhibitTitle)
}
func TestGetFieldExtractionByVersion_NotFound(t *testing.T) {
ctrl, cfg, documentID, _ := setupFieldExtractionsTestController(t)
ctx := t.Context()
// Create only one version
svc := fieldextraction.New(cfg)
filename := "test.pdf"
contractTitle := "Test Contract"
_, err := svc.CreateFieldExtraction(ctx, &fieldextraction.CreateFieldExtractionInput{
DocumentID: documentID,
SingleFields: &repository.AddFieldExtractionParams{
Documentid: documentID,
Filename: &filename,
Contracttitle: &contractTitle,
Createdby: "user@example.com",
},
ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{},
})
require.NoError(t, err)
// Try to get version 5 (which doesn't exist)
e := echo.New()
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=5", documentID), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
params := queryapi.GetFieldExtractionByVersionParams{
DocumentId: queryapi.DocumentID(documentID),
Version: 5,
}
err = ctrl.GetFieldExtractionByVersion(c, params)
require.Error(t, err)
httpErr, ok := err.(*echo.HTTPError)
require.True(t, ok)
assert.Equal(t, http.StatusNotFound, httpErr.Code)
}
func TestGetFieldExtractionByVersion_InvalidDocumentID(t *testing.T) {
ctrl, _, _, _ := setupFieldExtractionsTestController(t)
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/field-extractions/version?documentId=&version=1", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
params := queryapi.GetFieldExtractionByVersionParams{
DocumentId: queryapi.DocumentID(uuid.Nil),
Version: 1,
}
err := ctrl.GetFieldExtractionByVersion(c, params)
require.Error(t, err)
httpErr, ok := err.(*echo.HTTPError)
require.True(t, ok)
assert.Equal(t, http.StatusBadRequest, httpErr.Code)
}
func TestGetFieldExtractionByVersion_InvalidVersion(t *testing.T) {
ctrl, _, documentID, _ := setupFieldExtractionsTestController(t)
e := echo.New()
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=0", documentID), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
params := queryapi.GetFieldExtractionByVersionParams{
DocumentId: queryapi.DocumentID(documentID),
Version: 0, // Invalid: version must be >= 1
}
err := ctrl.GetFieldExtractionByVersion(c, params)
require.Error(t, err)
httpErr, ok := err.(*echo.HTTPError)
require.True(t, ok)
assert.Equal(t, http.StatusBadRequest, httpErr.Code)
}
func TestGetFieldExtractionByVersion_NoExtractions(t *testing.T) {
ctrl, _, documentID, _ := setupFieldExtractionsTestController(t)
// Document exists but has no field extractions
e := echo.New()
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/field-extractions/version?documentId=%s&version=1", documentID), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
params := queryapi.GetFieldExtractionByVersionParams{
DocumentId: queryapi.DocumentID(documentID),
Version: 1,
}
err := ctrl.GetFieldExtractionByVersion(c, params)
require.Error(t, err)
httpErr, ok := err.(*echo.HTTPError)
require.True(t, ok)
assert.Equal(t, http.StatusNotFound, httpErr.Code)
}
// Helper function to create string pointer
func ptr(s string) *string {
return &s