Openemr external coverage annotations - #2
Open
adunsulag wants to merge 18 commits into
Open
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
adunsulag
pushed a commit
that referenced
this pull request
Jan 29, 2026
Fixes openemr#8244 #### Short description of what this resolves: Under certain circumstances (not yet identified at the time of this PR), the edit button for questionnaire responses returns a 500 Internal Server Error and the following PHP error: ``` PHP Fatal error: Uncaught Error: Call to undefined function formFetch() in /var/www/localhost/htdocs/openemr/interface/forms/questionnaire_assessments/questionnaire_assessments.php:71 Stack trace: #0 /var/www/localhost/htdocs/openemr/interface/forms/questionnaire_assessments/view.php(14): require() #1 /var/www/localhost/htdocs/openemr/interface/patient_file/encounter/view_form.php(50): require_once('...') #2 {main} thrown in /var/www/localhost/htdocs/openemr/interface/forms/questionnaire_assessments/questionnaire_assessments.php on line 71 ``` #### Changes proposed in this pull request: Explicitly include api.inc.php in questionnaire_assessments.php to guarantee `formFetch()` is always defined. #### Does your code include anything generated by an AI Engine? Yes / No No Co-authored-by: bban160 <bban160@users.noreply.github.com>
adunsulag
pushed a commit
that referenced
this pull request
Mar 18, 2026
Fixes openemr#8244 #### Short description of what this resolves: Under certain circumstances (not yet identified at the time of this PR), the edit button for questionnaire responses returns a 500 Internal Server Error and the following PHP error: ``` PHP Fatal error: Uncaught Error: Call to undefined function formFetch() in /var/www/localhost/htdocs/openemr/interface/forms/questionnaire_assessments/questionnaire_assessments.php:71 Stack trace: #0 /var/www/localhost/htdocs/openemr/interface/forms/questionnaire_assessments/view.php(14): require() #1 /var/www/localhost/htdocs/openemr/interface/patient_file/encounter/view_form.php(50): require_once('...') #2 {main} thrown in /var/www/localhost/htdocs/openemr/interface/forms/questionnaire_assessments/questionnaire_assessments.php on line 71 ``` #### Changes proposed in this pull request: Explicitly include api.inc.php in questionnaire_assessments.php to guarantee `formFetch()` is always defined. #### Does your code include anything generated by an AI Engine? Yes / No No Co-authored-by: bban160 <bban160@users.noreply.github.com>
adunsulag
pushed a commit
that referenced
this pull request
Jun 20, 2026
<!-- Thanks for sending a pull request! Your PR title must follow Conventional Commits: type(scope): description Examples: feat(api): add patient search, fix(calendar): correct date parsing See CONTRIBUTING.md for details Please provide context about the nature of your change so that reviewers understand the motivation and we can generate changelogs. If this resolves an existing issue, link to one or more issues in the short description section, e.g. `Fixes openemr#12345`. --> #### Short description of what this changes or resolves: Password expiration warnings were not displaying. #### Changes proposed in this pull request: Display them. Also something weird with `phpstan` had to add `ccdaservice/node_modules` to the exclude path since using easy dev prek. ``` ------ ----------------------------------------------------------------------- Line ccdaservice/node_modules/flatted/php/flatted.php ------ ----------------------------------------------------------------------- 22 Property FlattedString::$value has no type specified. 🪪 missingType.property 23 Method FlattedString::__construct() has parameter $value with no type specified. 🪪 missingType.parameter 31 Method Flatted::parse() has no return type specified. 🪪 missingType.return 31 Method Flatted::parse() has parameter $assoc with no type specified. 🪪 missingType.parameter 31 Method Flatted::parse() has parameter $depth with no type specified. 🪪 missingType.parameter 31 Method Flatted::parse() has parameter $json with no type specified. 🪪 missingType.parameter 31 Method Flatted::parse() has parameter $options with no type specified. 🪪 missingType.parameter 36 Parameter #1 $json of function json_decode expects string, mixed given. 🪪 argument.type 36 Parameter #2 $array of function array_map expects array, mixed given. 🪪 argument.type 36 Parameter #2 $associative of function json_decode expects bool|null, mixed given. 🪪 argument.type 36 Parameter #3 $depth of function json_decode expects int<1, max>, mixed given. 🪪 argument.type 36 Parameter #4 $flags of function json_decode expects int, mixed given. 🪪 argument.type 49 Method Flatted::stringify() has no return type specified. 🪪 missingType.return 49 Method Flatted::stringify() has parameter $depth with no type specified. 🪪 missingType.parameter 49 Method Flatted::stringify() has parameter $options with no type specified. 🪪 missingType.parameter 49 Method Flatted::stringify() has parameter $value with no type specified. 🪪 missingType.parameter 55 Parameter #1 $value of function intval expects array|bool|float|GMP|int|resource|SimpleXMLElement|string|null, mixed given. 🪪 argument.type 56 Parameter #1 $value of function count expects array|Countable, mixed given. 🪪 argument.type 57 Cannot access offset int on mixed. 🪪 offsetAccess.nonOffsetAccessible 60 Parameter #2 $flags of function json_encode expects int, mixed given. 🪪 argument.type 60 Parameter #3 $depth of function json_encode expects int<1, max>, mixed given. 🪪 argument.type 64 Method Flatted::asString() has no return type specified. 🪪 missingType.return 64 Method Flatted::asString() has parameter $value with no type specified. 🪪 missingType.parameter 64 Static method Flatted::asString() is unused. 🪪 method.unused 68 Method Flatted::index() has no return type specified. 🪪 missingType.return 68 Method Flatted::index() has parameter $input with no type specified. 🪪 missingType.parameter 68 Method Flatted::index() has parameter $known with no type specified. 🪪 missingType.parameter 68 Method Flatted::index() has parameter $value with no type specified. 🪪 missingType.parameter 69 Cannot access an offset on mixed. 🪪 offsetAccess.nonOffsetAccessible 70 Parameter #1 $value of function count expects array|Countable, mixed given. 🪪 argument.type 71 Cannot access an offset on mixed. 🪪 offsetAccess.nonOffsetAccessible 71 Cannot access property $key on mixed. 🪪 property.nonObject 72 Cannot access an offset on mixed. 🪪 offsetAccess.nonOffsetAccessible 72 Cannot access property $value on mixed. 🪪 property.nonObject 76 Method Flatted::keys() has no return type specified. 🪪 missingType.return 76 Method Flatted::keys() has parameter $value with no type specified. 🪪 missingType.parameter 77 Parameter #1 $object of class ReflectionObject constructor expects object, mixed given. 🪪 argument.type 85 Method Flatted::loop() has no return type specified. 🪪 missingType.return 85 Method Flatted::loop() has parameter $input with no type specified. 🪪 missingType.parameter 85 Method Flatted::loop() has parameter $keys with no type specified. 🪪 missingType.parameter 85 Method Flatted::loop() has parameter $obj with no type specified. 🪪 missingType.parameter 85 Method Flatted::loop() has parameter $output with no type specified. 🪪 missingType.parameter 85 Method Flatted::loop() has parameter $set with no type specified. 🪪 missingType.parameter 86 Argument of an invalid type mixed supplied for foreach, only iterables are supported. 🪪 foreach.nonIterable 87 Cannot access offset mixed on mixed. 🪪 offsetAccess.nonOffsetAccessible 89 Cannot access offset mixed on mixed. 🪪 offsetAccess.nonOffsetAccessible 94 Method Flatted::relate() has no return type specified. 🪪 missingType.return 94 Method Flatted::relate() has parameter $input with no type specified. 🪪 missingType.parameter 94 Method Flatted::relate() has parameter $known with no type specified. 🪪 missingType.parameter 94 Method Flatted::relate() has parameter $value with no type specified. 🪪 missingType.parameter 96 Cannot access property $key on mixed. 🪪 property.nonObject 96 Parameter #2 $haystack of function array_search expects array, mixed given. 🪪 argument.type 98 Cannot access offset int|string on mixed. 🪪 offsetAccess.nonOffsetAccessible 98 Cannot access property $value on mixed. 🪪 property.nonObject 104 Method Flatted::ref() has no return type specified. 🪪 missingType.return 104 Method Flatted::ref() has parameter $input with no type specified. 🪪 missingType.parameter 104 Method Flatted::ref() has parameter $key with no type specified. 🪪 missingType.parameter 104 Method Flatted::ref() has parameter $obj with no type specified. 🪪 missingType.parameter 104 Method Flatted::ref() has parameter $output with no type specified. 🪪 missingType.parameter 104 Method Flatted::ref() has parameter $set with no type specified. 🪪 missingType.parameter 104 Method Flatted::ref() has parameter $value with no type specified. 🪪 missingType.parameter 105 Parameter #2 $haystack of function in_array expects array, mixed given. 🪪 argument.type 106 Cannot access an offset on mixed. 🪪 offsetAccess.nonOffsetAccessible 109 Parameter #2 $haystack of function in_array expects array, mixed given. 🪪 argument.type 110 Cannot access an offset on mixed. 🪪 offsetAccess.nonOffsetAccessible 117 Cannot access offset mixed on mixed. 🪪 offsetAccess.nonOffsetAccessible 121 Method Flatted::transform() has no return type specified. 🪪 missingType.return 121 Method Flatted::transform() has parameter $input with no type specified. 🪪 missingType.parameter 121 Method Flatted::transform() has parameter $known with no type specified. 🪪 missingType.parameter 121 Method Flatted::transform() has parameter $value with no type specified. 🪪 missingType.parameter 133 Argument of an invalid type mixed supplied for foreach, only iterables are supported. 🪪 foreach.nonIterable 140 Method Flatted::wrap() has no return type specified. 🪪 missingType.return 140 Method Flatted::wrap() has parameter $value with no type specified. 🪪 missingType.parameter 140 Static method Flatted::wrap() is unused. 🪪 method.unused 149 Argument of an invalid type mixed supplied for foreach, only iterables are supported. 🪪 foreach.nonIterable ------ ----------------------------------------------------------------------- [ERROR] Found 75 errors ``` #### Was an AI assistant used? Yes consulted with claude.ai. <!-- If yes, add an `Assisted-by` trailer to each commit that used AI assistance: ``` git commit --trailer "Assisted-by: Claude Code" -m "fix(calendar): correct date parsing" ``` Use the name of the specific tool (e.g. `GitHub Copilot`, `Claude Code`, `ChatGPT`). If the AI made the commit(s), this trailer was probably added automatically. -->
adunsulag
pushed a commit
that referenced
this pull request
Jun 20, 2026
…nsurance + pharmacy) (openemr#12529) **Bug:** saving an insurance company at *Practice Settings → Insurance Company* — or a pharmacy at *Procedures → Pharmacies* — throws a `TypeError` when the **Phone** (or **Fax**) field holds a value that `PhoneNumber::tryParse()` accepts but that does not yield a 10-digit NANP national number — e.g. a 7-digit local entry like `555-1234` or an over-long entry like `555-123-45678`. The user-visible trace from the insurance flow: ``` TypeError: OpenEMR\Services\PhoneNumberService::getPhoneParts(): Argument #1 ($phone_number) must be of type string, null given, called in src/Services/PhoneNumberService.php on line 61 #0 src/Services/PhoneNumberService.php(61): PhoneNumberService->getPhoneParts() #1 library/classes/InsuranceCompany.class.php(346): PhoneNumberService->insert() #2 controllers/C_InsuranceCompany.class.php(89): C_InsuranceCompany->edit_action_process() ``` **Why:** `library/classes/InsuranceCompany.class.php::persist()` and `library/classes/Pharmacy.class.php::persist()` both read each typed phone via `$phone->phoneNumber->getNationalDigits()` and feed the result straight into `PhoneNumberService::insert()`. `getNationalDigits()` returns `?string` — `null` whenever the parsed national number isn't exactly 10 digits — and `PhoneNumberService::getPhoneParts()` is type-hinted `string`, so passing `null` blows up before the row hits the database. Both classes got the buggy persist body from the same change: PR openemr#10326 *"refactor(validation): consolidate phone number handling using PhoneNumberService"* (merged 2026-01-27), which replaced the old per-`PhoneNumber`-object `$phone->persist($id)` call with the service-mediated insert and introduced `getNationalDigits()` simultaneously without a null-check between them. **Fix:** guard both `persist()` loops and skip phones the legacy `phone_numbers` table (the `area_code` / `prefix` / `number` triple) cannot represent. That mirrors the existing pattern on the read side of both classes, which already drops entries where `TypedPhoneNumber::tryCreate()` returns `null`. The user's save then succeeds; the invalid phone is silently dropped rather than crashing the request — matching what `set_number()` already does for outright unparseable input. **Behavior note.** Silent-drop is the established convention in both `InsuranceCompany::set_number()` and `Pharmacy::set_number()` (they already silently return when `TypedPhoneNumber::tryCreate()` returns `null`), so this fix doesn't introduce a new UX pattern. Surface-level: pre-openemr#10326 the same input quietly wrote a row with empty `area_code`/`prefix`/`number` columns (silent data corruption); this fix doesn't write a junk row. A proper form-level *"Phone must be a 10-digit number"* validation error belongs in a separate UX-focused PR — the underlying `phone_numbers` schema is itself NANP-only and would need to grow to support international formats first. **Tests:** - `InsuranceCompanyServiceTest::testLegacyPersistSkipsPhoneWithoutTenDigitNationalNumber` — drives the legacy InsuranceCompany class with `'555-1234'` and asserts persist completes and writes no `phone_numbers` row. - `PharmacyPersistTest::testLegacyPersistSkipsPhoneWithoutTenDigitNationalNumber` — parallel test for the Pharmacy class. **Verified locally:** - Pre-fix: direct repro of both flows reproduces the exact reported `TypeError` (matched against the user's stack at `InsuranceCompany.class.php:346`; identical shape at `Pharmacy.class.php:227`). - Post-fix: same inputs persist cleanly; happy path `'555-123-4567'` still writes `{area_code: 555, prefix: 123, number: 4567}` to `phone_numbers` for both classes. - Pre-commit hook chain (phpstan / phpcbf / phpcs / rector / codespell / conventional-commits / composer-require-checker / php-syntax) all clean. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Phone persistence for insurance companies and pharmacies now safely skips phone values that can’t be represented in the legacy format, preventing persistence-time errors. * **Tests** * Added regression integration coverage to confirm that short/invalid phone numbers (e.g., missing a 10-digit national number) do not result in stored phone entries for both insurance and pharmacy records. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Testing code coverage.