Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: medicare flow with pverify #8

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,7 @@ VITE_SENTRY_PROJECT=
# String regex without the "/". Example:
# ^https:\/\/yourserver\.io\/api
VITE_SENTRY_TRACE_PROPAGATION_TARGET_REGEX=

PVERIFY_BASE_URL=https://api.pverify.com/API
PVERIFY_CLIENT_API_ID=
PVERIFY_CLIENT_SECRET=
3 changes: 3 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
'base_url' => env('PVERIFY_BASE_URL'),
'client_api_id' => env('PVERIFY_CLIENT_API_ID'),
'client_secret' => env('PVERIFY_CLIENT_SECRET'),
'sleep_seconds' => env('PVERIFY_SLEEP_SECONDS'),
'provider_npi' => env('PVERIFY_PROVIDER_NPI'),
'provider_last_name' => env('PVERIFY_PROVIDER_LAST_NAME'),
],

'dosespot' => [
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"Debugbar",
"Dispatchable",
"docblocks",
"doespots",
"dosespot",
"EHLO",
"Encrypter",
Expand Down
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ parameters:
ignoreErrors:
- '#^PHPUnit tests are not allowed\. Please use Pest PHP instead\. If this is a TestCase, make it abstract to pass validation\.$#'
- '#^Illuminate\\Support\\Facades\\[a-zA-Z0-9\\_]+ facade should not be used\.$#'
- '#^Cannot cast mixed to string\.$#'
- '#^Cannot cast mixed to int\.$#'
-
message: '#^Undefined variable: \$this$#'
path: tests/*
Expand Down
3 changes: 3 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Lightit\Insurance\App\Controllers\GetAvailableDMEProvidersController;
use Lightit\Insurance\App\Controllers\MedicareAdvantageEligibilityCheckController;
use Lightit\Insurance\App\Controllers\MedicareEligibilityCheckController;
use Lightit\Insurance\App\Controllers\RunEligibilityController;

/*
|--------------------------------------------------------------------------
Expand Down Expand Up @@ -43,3 +44,5 @@
Route::post('/medicare-advantage/eligibility-check', MedicareAdvantageEligibilityCheckController::class);

Route::get('/dme/providers', GetAvailableDMEProvidersController::class);

Route::post('/eligibility', RunEligibilityController::class);
2 changes: 2 additions & 0 deletions src/Backoffice/Payers/Domain/Models/Payer.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
* @method static \Illuminate\Database\Eloquent\Builder|Payer whereDataSyncId($value)
*
* @property-read Datasync|null $dataSync
* @property-read \Illuminate\Database\Eloquent\Collection<int, PayersDMEProvider> $payerDMEProviders
* @property-read int|null $payer_d_m_e_providers_count
*
* @mixin \Eloquent
*/
Expand Down
24 changes: 24 additions & 0 deletions src/Insurance/App/Controllers/RunEligibilityController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Lightit\Insurance\App\Controllers;

use Illuminate\Http\JsonResponse;
use Lightit\Insurance\App\Request\EligibilityCheckRequest;
use Lightit\Insurance\Domain\Actions\RunEligibilityAction;

class RunEligibilityController
{
public function __invoke(
EligibilityCheckRequest $request,
RunEligibilityAction $runEligibilityAction,
): JsonResponse {
$eligibilityData = $request->toDto();

$response = $runEligibilityAction->execute($eligibilityData);
return responder()
->success($response)
->respond();
}
}
24 changes: 24 additions & 0 deletions src/Insurance/App/Exceptions/NotEligibleException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Lightit\Insurance\App\Exceptions;

use Flugg\Responder\Exceptions\Http\HttpException;

class NotEligibleException extends HttpException
{
/**
* An HTTP status code.
*
* @var int
*/
protected $status = 422;

/**
* An error code.
*
* @var string|null
*/
protected $errorCode = 'not_eligible';
}
75 changes: 75 additions & 0 deletions src/Insurance/App/Request/EligibilityCheckRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace Lightit\Insurance\App\Request;

use Carbon\Carbon;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;
use Lightit\Insurance\Domain\DataTransferObjects\EligibilityCheckDto;
use Lightit\Shared\App\Enums\USState;

class EligibilityCheckRequest extends FormRequest
{
public const FIRST_NAME = 'first_name';
public const LAST_NAME = 'last_name';
public const DOB = 'dob';

public const STREET = 'street';
public const CITY = 'city';
public const STATE = 'state';
public const ZIP = 'zip';

public const PLAN_TYPE = 'plan_type';
public const DIABETES_TYPE = 'diabetes_type';
public const DIABETES_MANAGEMENT = 'diabetes_management';

/**
* @return array<string, mixed>
*/
public function rules(): array
{
return [
self::FIRST_NAME => ['required', 'string'],
self::LAST_NAME => ['required', 'string'],
self::DOB => ['required', 'date'],

self::STREET => ['required', 'string'],
self::CITY => ['required', 'string'],
self::STATE => ['required', new Enum(USState::class)],
self::ZIP => ['required', 'string'],

self::PLAN_TYPE => ['required', 'string'],
self::DIABETES_TYPE => ['required', 'string'],
];
}

protected function prepareForValidation()
{
if ($this->has('state') && is_string($this->state)) {
$this->merge([
'state' => strtoupper($this->state),
]);
}
}

public function toDto(): EligibilityCheckDto
{
/** @var Carbon $dob */
$dob = $this->date(self::DOB);

return new EligibilityCheckDto(
first_name: $this->string(self::FIRST_NAME)->toString(),
last_name: $this->string(self::LAST_NAME)->toString(),
dob: $dob,
street: $this->string(self::STREET)->toString(),
city: $this->string(self::CITY)->toString(),
state: USState::from($this->string(self::STATE)->toString()),
zip: $this->string(self::ZIP)->toString(),
plan_type: $this->string(self::PLAN_TYPE)->toString(),
diabetes_type: $this->string(self::DIABETES_TYPE)->toString(),
diabetes_management: $this->string(self::DIABETES_MANAGEMENT)->toString(),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

namespace Lightit\Insurance\Domain\Actions;

use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Lightit\Insurance\Domain\DataTransferObjects\MedicareAdvantageEligibilityCheckDto;
use Lightit\Insurance\Domain\DataTransferObjects\MedicareAdvantageEligibilityResponseDto;
use Lightit\Shared\Integrations\PVerify\DataTransferObjects\EligibilitySummaryRequestDTO;
use Lightit\Shared\Integrations\PVerify\DataTransferObjects\PVerifySubscriberDTO;
use Lightit\Shared\Integrations\PVerify\Requests\EligibilitySummary;
use Lightit\Shared\Integrations\PVerify\Requests\GetEligibilitySummary;
use Lightit\Shared\Integrations\PVerify\Requests\EligibilitySummaryRequest;
use Lightit\Shared\Integrations\PVerify\Requests\GetEligibilitySummaryResultsRequest;

class MedicareAdvantageEligibilityCheckAction
{
Expand All @@ -23,9 +25,14 @@ public function execute(
memberID: $getAvailableDMEProvidersDto->member_id,
);

$eligibilityRequest = new EligibilitySummary(
payerCode: $getAvailableDMEProvidersDto->payer,
subscriber: $subscriberDTO,
$eligibilityRequest = new EligibilitySummaryRequest(
new EligibilitySummaryRequestDTO(
firstName: $subscriberDTO->firstName,
lastName: $subscriberDTO->lastName,
dob: Carbon::parse($subscriberDTO->dob),
memberID: $subscriberDTO->memberID,
payerCode: $getAvailableDMEProvidersDto->payer,
)
);

$response = $eligibilityRequest->send();
Expand All @@ -37,7 +44,7 @@ public function execute(
}

sleep(5);
$eligibilityResultRequest = new GetEligibilitySummary(
$eligibilityResultRequest = new GetEligibilitySummaryResultsRequest(
requestId: $eligibilityResponse['RequestID'],
);
$eligibilityResultResponse = $eligibilityResultRequest->send()->json();
Expand Down
15 changes: 11 additions & 4 deletions src/Insurance/Domain/Actions/MedicareEligibilityCheckAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

namespace Lightit\Insurance\Domain\Actions;

use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Lightit\Insurance\Domain\DataTransferObjects\MedicareEligibilityCheckDto;
use Lightit\Insurance\Domain\DataTransferObjects\MedicareEligibilityResponseDto;
use Lightit\Shared\Integrations\PVerify\DataTransferObjects\EligibilitySummaryRequestDTO;
use Lightit\Shared\Integrations\PVerify\DataTransferObjects\PVerifySubscriberDTO;
use Lightit\Shared\Integrations\PVerify\Requests\EligibilitySummary;
use Lightit\Shared\Integrations\PVerify\Requests\EligibilitySummaryRequest;

class MedicareEligibilityCheckAction
{
Expand All @@ -24,9 +26,14 @@ public function execute(MedicareEligibilityCheckDto $getAvailableDMEProvidersDto
memberID: $getAvailableDMEProvidersDto->member_id,
);

$eligibilityRequest = new EligibilitySummary(
payerCode: self::MEDICARE_PAYER_CODE,
subscriber: $subscriberDTO,
$eligibilityRequest = new EligibilitySummaryRequest(
new EligibilitySummaryRequestDTO(
firstName: $subscriberDTO->firstName,
lastName: $subscriberDTO->lastName,
dob: Carbon::parse($subscriberDTO->dob),
memberID: $subscriberDTO->memberID,
payerCode: self::MEDICARE_PAYER_CODE,
)
);

$response = $eligibilityRequest->send();
Expand Down
55 changes: 55 additions & 0 deletions src/Insurance/Domain/Actions/RunEligibilityAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Lightit\Insurance\Domain\Actions;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Lightit\Insurance\Domain\DataTransferObjects\EligibilityCheckDto;
use Lightit\Insurance\Domain\DataTransferObjects\GetAvailableDMEProvidersDto;
use Lightit\Shared\Domain\Models\PayersDMEProvider;

class RunEligibilityAction
{
public function __construct(
private readonly RunMbiLookupAction $mbiLookupAction,
private readonly RunPVerifyEligibilitySummaryAction $pVerifyEligibilitySummaryAction,
private readonly GetAvailableDMEProvidersAction $getAvailableDMEProvidersAction,
) {
}

/**
* @return Collection<int, PayersDMEProvider>
*/
public function execute(EligibilityCheckDto $eligibilityCheckData): Collection
{
if ($this->isMedicare($eligibilityCheckData)) {
$mbiLookupResponse = $this->mbiLookupAction->execute($eligibilityCheckData);
$eligibilityResponse = $this->pVerifyEligibilitySummaryAction->execute(
$eligibilityCheckData,
$mbiLookupResponse
);

Log::info('Medicare eligible', ['response' => $eligibilityResponse]);

return $this->getAvailableDMEProvidersAction->execute(
new GetAvailableDMEProvidersDto(
payer: $eligibilityResponse['PayerName'],
state: $eligibilityCheckData->state
)
);
}

//medicare advantage flow

//doespots flow

return collect([]);
}

private function isMedicare(EligibilityCheckDto $eligibilityCheckData): bool
{
return $eligibilityCheckData->dob->diffInYears(now()) >= 65 && $eligibilityCheckData->plan_type === 'medicare';
}
}
33 changes: 33 additions & 0 deletions src/Insurance/Domain/Actions/RunMbiLookupAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Lightit\Insurance\Domain\Actions;

use Lightit\Insurance\Domain\DataTransferObjects\EligibilityCheckDto;
use Lightit\Insurance\Domain\DataTransferObjects\MbiLookupRequestDto;
use Lightit\Shared\Integrations\PVerify\PVerifyConnector;
use Lightit\Shared\Integrations\PVerify\Requests\MbiLookupRequest;

class RunMbiLookupAction
{
public function __construct(
private readonly PVerifyConnector $connector,
) {
}

public function execute(EligibilityCheckDto $eligibilityCheckDto): array
{
$request = new MbiLookupRequest(
new MbiLookupRequestDto(
firstName: $eligibilityCheckDto->first_name,
lastName: $eligibilityCheckDto->last_name,
dob: $eligibilityCheckDto->dob,
)
);

$response = $this->connector->send($request);

return $response->json();
}
}
Loading