Skip to content

Commit 9519e51

Browse files
BCDA-9876: enable pac data v3 ssp (#1327)
## 🎫 Ticket https://jira.cms.gov/browse/BCDA-9876 ## πŸ›  Changes New Behavior: - SSP model entities can access both partially adjudicated and adjudicated claims data via BCDA v3 - KCC model entities can access only adjudicated claims data ## ℹ️ Context We don't plan to add any new model types for v1/v2 access. Like IOTA, any new models should be limited to v3. Going forward, the default will be access to both adjudicated and partially adjudicated claims data via v3. ## πŸ§ͺ Validation Unit test suite
1 parent 0cd811d commit 9519e51

File tree

7 files changed

+96
-5
lines changed

7 files changed

+96
-5
lines changed

β€Žbcda/service/config.goβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type Config struct {
3434
CutoffDuration time.Duration
3535
RateLimitConfig RateLimitConfig `conf:"rate_limit_config"`
3636
V1V2DenyRegexes []string `conf:"v1_v2_deny_regexes"`
37+
V3NoPartialClaimsModels []string `conf:"v3_no_partial_claims_models"`
3738
// Use the squash tag to allow the RunoutConfigs to avoid requiring the parameters
3839
// to be defined as a child of RunoutConfig.
3940
// Ex: Without the ,squash, we would have to have RunoutConfig.RUNOUT_CUTOFF_DATE_DAYS

β€Žbcda/service/service.goβ€Ž

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
goerrors "errors"
66
"fmt"
77
"regexp"
8+
"slices"
89
"strings"
910
"time"
1011

@@ -51,7 +52,8 @@ type service struct {
5152
bbBasePath string
5253

5354
// These are always searched in order and first matching config is used for any given ACO.
54-
acoConfigs []ACOConfig
55+
acoConfigs []ACOConfig
56+
v3NoPartialClaimsModels []string
5557
}
5658

5759
func NewService(r models.Repository, cfg *Config, basePath string) Service {
@@ -68,8 +70,9 @@ func NewService(r models.Repository, cfg *Config, basePath string) Service {
6870
claimThruDate: cfg.RunoutConfig.claimThru,
6971
CutoffDuration: cfg.RunoutConfig.CutoffDuration,
7072
},
71-
bbBasePath: basePath,
72-
acoConfigs: cfg.ACOConfigs,
73+
bbBasePath: basePath,
74+
acoConfigs: cfg.ACOConfigs,
75+
v3NoPartialClaimsModels: cfg.V3NoPartialClaimsModels,
7376
}
7477
}
7578

@@ -277,6 +280,15 @@ func (s *service) createQueueJobs(ctx context.Context, args worker_types.Prepare
277280
return nil, fmt.Errorf("failed to load or match ACO config (or potentially no ACO Configs set), CMS ID: %+v", args.CMSID)
278281
}
279282

283+
effectiveDataTypes := acoCfg.Data
284+
if args.BFDPath == constants.BFDV3Path {
285+
excluded := slices.Contains(s.v3NoPartialClaimsModels, acoCfg.Model)
286+
if !excluded && !slices.Contains(acoCfg.Data, constants.PartiallyAdjudicated) {
287+
effectiveDataTypes = append([]string(nil), acoCfg.Data...)
288+
effectiveDataTypes = append(effectiveDataTypes, constants.PartiallyAdjudicated)
289+
}
290+
}
291+
280292
for _, rt := range args.ResourceTypes {
281293
maxBeneficiaries, err := getMaxBeneCount(rt)
282294
if err != nil {
@@ -290,7 +302,7 @@ func (s *service) createQueueJobs(ctx context.Context, args worker_types.Prepare
290302
jobIDs = append(jobIDs, fmt.Sprint(b.ID))
291303
if len(jobIDs) >= maxBeneficiaries || rowCount >= len(beneficiaries) {
292304
// Create separate jobs for each data type if needed
293-
for _, dataType := range acoCfg.Data {
305+
for _, dataType := range effectiveDataTypes {
294306
// conditions.TransactionTime references the last time adjudicated data
295307
// was updated in the BB client. If we are queuing up a partially-adjudicated
296308
// data job, we need to assume that the adjudicated and partially-adjudicated

β€Žbcda/service/service_test.goβ€Ž

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,6 +1844,76 @@ func TestCreateQueueJobs_Fail_ACOConfigMismatch(t *testing.T) {
18441844
assert.ErrorContains(t, err, "failed to load or match ACO config (or potentially no ACO Configs set), CMS ID:")
18451845
}
18461846

1847+
func TestCreateQueueJobs_V3_SSP_GetsPartiallyAdjudicated(t *testing.T) {
1848+
// SSP with only adjudicated in config gets both adjudicated and partially-adjudicated jobs when using v3.
1849+
sspACO := ACOConfig{
1850+
Model: "SSP",
1851+
patternExp: regexp.MustCompile(`^A\d{4}`),
1852+
Data: []string{constants.Adjudicated},
1853+
}
1854+
cfg := &Config{
1855+
CutoffDuration: -50 * time.Hour,
1856+
SuppressionLookbackDays: int(30),
1857+
RunoutConfig: RunoutConfig{CutoffDuration: defaultRunoutCutoff, claimThru: defaultRunoutClaimThru},
1858+
ACOConfigs: []ACOConfig{sspACO},
1859+
V3NoPartialClaimsModels: []string{"CKCC"},
1860+
}
1861+
repository := models.NewMockRepository(t)
1862+
svc := NewService(repository, cfg, "").(*service)
1863+
ctx := context.WithValue(context.Background(), middleware.CtxTransactionKey, "test-txn")
1864+
args := worker_types.PrepareJobArgs{
1865+
Job: models.Job{ID: 1, TransactionTime: time.Now()},
1866+
CMSID: "A1234",
1867+
ACOID: uuid.NewUUID(),
1868+
BFDPath: constants.BFDV3Path,
1869+
ResourceTypes: []string{"ExplanationOfBenefit", "Claim"},
1870+
CreationTime: time.Now(),
1871+
}
1872+
benes := []*models.CCLFBeneficiary{getCCLFBeneficiary(1, "MBI1")}
1873+
jobs, err := svc.createQueueJobs(ctx, args, time.Time{}, benes)
1874+
assert.NoError(t, err)
1875+
// EOB supports only adjudicated; Claim supports only partially-adjudicated. So we get 2 jobs (one of each data type).
1876+
assert.Len(t, jobs, 2)
1877+
dataTypes := make([]string, len(jobs))
1878+
for i, j := range jobs {
1879+
dataTypes[i] = j.DataType
1880+
}
1881+
assert.Contains(t, dataTypes, constants.Adjudicated)
1882+
assert.Contains(t, dataTypes, constants.PartiallyAdjudicated)
1883+
}
1884+
1885+
func TestCreateQueueJobs_V3_KCC_AdjudicatedOnly(t *testing.T) {
1886+
// KCC (CKCC) with only adjudicated in config gets only adjudicated jobs in v3 (no PAC).
1887+
kccACO := ACOConfig{
1888+
Model: "CKCC",
1889+
patternExp: regexp.MustCompile(`C\d{4}`),
1890+
Data: []string{constants.Adjudicated},
1891+
}
1892+
cfg := &Config{
1893+
CutoffDuration: -50 * time.Hour,
1894+
SuppressionLookbackDays: int(30),
1895+
RunoutConfig: RunoutConfig{CutoffDuration: defaultRunoutCutoff, claimThru: defaultRunoutClaimThru},
1896+
ACOConfigs: []ACOConfig{kccACO},
1897+
V3NoPartialClaimsModels: []string{"CKCC"},
1898+
}
1899+
repository := models.NewMockRepository(t)
1900+
svc := NewService(repository, cfg, "").(*service)
1901+
ctx := context.WithValue(context.Background(), middleware.CtxTransactionKey, "test-txn")
1902+
args := worker_types.PrepareJobArgs{
1903+
Job: models.Job{ID: 1, TransactionTime: time.Now()},
1904+
CMSID: "C5678",
1905+
ACOID: uuid.NewUUID(),
1906+
BFDPath: constants.BFDV3Path,
1907+
ResourceTypes: []string{"ExplanationOfBenefit"},
1908+
CreationTime: time.Now(),
1909+
}
1910+
benes := []*models.CCLFBeneficiary{getCCLFBeneficiary(1, "MBI1")}
1911+
jobs, err := svc.createQueueJobs(ctx, args, time.Time{}, benes)
1912+
assert.NoError(t, err)
1913+
assert.Len(t, jobs, 1)
1914+
assert.Equal(t, constants.Adjudicated, jobs[0].DataType)
1915+
}
1916+
18471917
func TestSetClaimsDate_Runout(t *testing.T) {
18481918
pArgs := worker_types.PrepareJobArgs{
18491919
CMSID: "A0000",

β€Žconf/configs/dev.ymlβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,5 @@ rate_limit_config:
8080
acos: []
8181
v3_enabled_acos: []
8282
v1_v2_deny_regexes: []
83+
v3_no_partial_claims_models:
84+
- "CKCC"

β€Žconf/configs/prod.ymlβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,6 @@ rate_limit_config:
8080
acos: []
8181
v3_enabled_acos:
8282
- "TEST994"
83-
v1_v2_deny_regexes: ["IOTA\\d{3}"]
83+
v1_v2_deny_regexes: ["IOTA\\d{3}"]
84+
v3_no_partial_claims_models:
85+
- "CKCC"

β€Žconf/configs/sandbox.ymlβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,5 @@ rate_limit_config:
8787
acos: ["SBXBM0002"]
8888
v3_enabled_acos: []
8989
v1_v2_deny_regexes: []
90+
v3_no_partial_claims_models:
91+
- "CKCC"

β€Žconf/configs/test.ymlβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,5 @@ rate_limit_config:
8080
acos: []
8181
v3_enabled_acos: []
8282
v1_v2_deny_regexes: []
83+
v3_no_partial_claims_models:
84+
- "CKCC"

0 commit comments

Comments
Β (0)