Skip to content

Openemr external coverage annotations - #2

Open
adunsulag wants to merge 18 commits into
masterfrom
openemr-external-coverage-annotations
Open

Openemr external coverage annotations#2
adunsulag wants to merge 18 commits into
masterfrom
openemr-external-coverage-annotations

Conversation

@adunsulag

Copy link
Copy Markdown

Testing code coverage.

@codecov

codecov Bot commented May 29, 2025

Copy link
Copy Markdown

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 -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants