Skip to content

Fix CSV and directory export to use family address fallback#7964

Open
DawoudIO wants to merge 4 commits intomasterfrom
fix/issue-7937-csv-address-export
Open

Fix CSV and directory export to use family address fallback#7964
DawoudIO wants to merge 4 commits intomasterfrom
fix/issue-7937-csv-address-export

Conversation

@DawoudIO
Copy link
Contributor

@DawoudIO DawoudIO commented Feb 7, 2026

Summary

Fixes #7937 - Family and person addresses don't export to CSV and some are not included in Church Directory

When exporting CSV reports or generating church directory PDFs, persons without personal address data now fall back to their family's address information. This ensures all family members appear in exports with complete address details, even if they haven't entered personal addresses.

Changes

CSV Export (src/CSVCreateFile.php)

  • Modified address field logic to use family fallback pattern: !empty($per_Field) ? $per_Field : ($fam_Field ?? '')
  • Applied to: Address1, Address2, City, State, Zip, Country, HomePhone, Email
  • Works for both default and rollup export formats

Directory Report (src/Reports/DirectoryReport.php)

  • Applied same family address fallback pattern for individual person entries
  • Ensures persons without personal addresses still appear in PDF directory with family's address

Tests (cypress/e2e/ui/reports/standard.csv.reports.spec.js)

  • Added 2 new tests verifying CSV exports include address columns
  • Tests both default and rollup formats with proper POST parameters
  • All 8 tests pass

Why

Previously, when a person had no personal address entered but belonged to a family with address data:

  • CSV exports showed blank address fields
  • Directory reports omitted address information

This was unexpected behavior since most church members share their family's address. The fix provides a sensible fallback while still respecting any personal address data when present.

Testing

Files Changed

When exporting CSV or generating church directory, persons without
personal addresses now fall back to their family's address data.
This ensures members are included in exports with complete address
information even if they haven't entered personal address details.

Fixes #7937
@DawoudIO DawoudIO added this to the 6.8.1 milestone Feb 7, 2026
Copilot AI review requested due to automatic review settings February 7, 2026 21:24
@DawoudIO DawoudIO requested a review from a team as a code owner February 7, 2026 21:24
@DawoudIO DawoudIO requested review from DAcodedBEAT, MrClever, bigtigerku, grayeul and respencer and removed request for a team February 7, 2026 21:24
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses #7937 by ensuring that CSV exports and the PDF church directory include address/contact info for people who don’t have personal address data, by falling back to their family’s address/contact fields.

Changes:

  • Update CSV export row-building to prefer person address/contact fields but fall back to family fields when person fields are empty.
  • Update Directory report rendering for single-person entries to use the same family fallback behavior.
  • Add Cypress coverage to assert address columns appear in CSV exports (default and rollup).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/CSVCreateFile.php Adds person→family fallback for address/contact fields when generating CSV rows.
src/Reports/DirectoryReport.php Adds person→family fallback for address/contact fields for single-person directory entries.
cypress/e2e/ui/reports/standard.csv.reports.spec.js Adds two tests asserting address columns exist in exported CSV headers.

Comment on lines 30 to 37
cy.request({
method: "POST",
url: "/CSVCreateFile.php",
form: true,
body: {
output: "csv",
format: "default",
familyonly: "false",
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The request body uses format (lowercase), but CSVCreateFile.php reads $_POST['Format'] (capital F) and the UI form uses name="Format" (see src/CSVExport.php). With the current payload this test may not exercise the intended code path (and can trigger unintended default filters). Update the POST parameter to Format (and consider matching the UI values like Default/Rollup), and include any required date-range fields so the export returns real rows.

Copilot uses AI. Check for mistakes.
form: true,
body: {
output: "csv",
format: "rollup",
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here: the test posts format: "rollup", but the endpoint expects Format (capital F). As written, this may not actually be testing rollup behavior and could silently return an empty export/header-only response due to missing expected filters. Use Format: "Rollup" (or at least Format: "rollup") and post the other form fields the script assumes are present.

Suggested change
format: "rollup",
Format: "Rollup",

Copilot uses AI. Check for mistakes.
Comment on lines 379 to 403
if ($sFormat === 'rollup') {
// Even in rollup format, use person data (no family inheritance)
$sHomePhone = $per_HomePhone ?? '';
// Rollup format: use person data with family fallback for address/contact fields
$sHomePhone = !empty($per_HomePhone) ? $per_HomePhone : ($fam_HomePhone ?? '');
$sWorkPhone = $per_WorkPhone ?? '';
$sCellPhone = $per_CellPhone ?? '';
$sCountry = $per_Country ?? '';
$sAddress1 = $per_Address1 ?? '';
$sAddress2 = $per_Address2 ?? '';
$sCity = $per_City ?? '';
$sState = $per_State ?? '';
$sZip = $per_Zip ?? '';
$sEmail = $per_Email ?? '';
$sCountry = !empty($per_Country) ? $per_Country : ($fam_Country ?? '');
$sAddress1 = !empty($per_Address1) ? $per_Address1 : ($fam_Address1 ?? '');
$sAddress2 = !empty($per_Address2) ? $per_Address2 : ($fam_Address2 ?? '');
$sCity = !empty($per_City) ? $per_City : ($fam_City ?? '');
$sState = !empty($per_State) ? $per_State : ($fam_State ?? '');
$sZip = !empty($per_Zip) ? $per_Zip : ($fam_Zip ?? '');
$sEmail = !empty($per_Email) ? $per_Email : ($fam_Email ?? '');
} else {
// Individual data - use person data only
$sHomePhone = $per_HomePhone ?? '';
// Default format: use person data with family fallback for address/contact fields
$sHomePhone = !empty($per_HomePhone) ? $per_HomePhone : ($fam_HomePhone ?? '');
$sWorkPhone = $per_WorkPhone ?? '';
$sCellPhone = $per_CellPhone ?? '';
$sCountry = $per_Country ?? '';
$sAddress1 = $per_Address1 ?? '';
$sAddress2 = $per_Address2 ?? '';
$sCity = $per_City ?? '';
$sState = $per_State ?? '';
$sZip = $per_Zip ?? '';
$sEmail = $per_Email ?? '';
$sCountry = !empty($per_Country) ? $per_Country : ($fam_Country ?? '');
$sAddress1 = !empty($per_Address1) ? $per_Address1 : ($fam_Address1 ?? '');
$sAddress2 = !empty($per_Address2) ? $per_Address2 : ($fam_Address2 ?? '');
$sCity = !empty($per_City) ? $per_City : ($fam_City ?? '');
$sState = !empty($per_State) ? $per_State : ($fam_State ?? '');
$sZip = !empty($per_Zip) ? $per_Zip : ($fam_Zip ?? '');
$sEmail = !empty($per_Email) ? $per_Email : ($fam_Email ?? '');
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rollup and default branches now perform the same address/contact-field assignments. This conditional duplication makes the code harder to maintain (any future change must be applied twice). Consider collapsing this into a single assignment block (or a small helper) and only branching where rollup/default behavior actually differs.

Copilot uses AI. Check for mistakes.
- Fix POST parameter name: use 'Format' (capital F) to match CSVCreateFile.php
- Deduplicate address fallback code: remove conditional since rollup and default
  use identical address/contact field assignments
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment on lines 28 to 56
it("should include address columns in CSV export with family fallback", () => {
// Test default format includes address fields when requested
cy.request({
method: "POST",
url: "/CSVCreateFile.php",
form: true,
body: {
output: "csv",
Format: "default",
familyonly: "false",
Source: "all",
Address1: "1",
Address2: "1",
City: "1",
State: "1",
Zip: "1"
}
}).then((response) => {
expect(response.status).to.eq(200);
expect(response.headers["content-type"]).to.include("text/csv");

// Verify CSV header contains address columns
const lines = response.body.split('\n');
expect(lines.length).to.be.greaterThan(1);
const header = lines[0].toLowerCase();
expect(header).to.include("address 1");
expect(header).to.include("city");
expect(header).to.include("state");
});
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new Cypress tests only verify that the CSV headers include address columns; they don’t validate the actual behavior introduced by this PR (person address fields falling back to family values when personal values are empty). As written, these tests would still pass even if the fallback logic were broken. Consider asserting at least one exported data row contains non-empty address values for a known person-without-address / family-with-address case (or creating such a record during the test) and also asserting the body doesn’t contain PHP fatal/parse errors like the existing test does.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines 377 to 388
// Use person data with fallback to family data for addresses/contact
// This ensures members without personal addresses still get exported with their family's address
$sHomePhone = !empty($per_HomePhone) ? $per_HomePhone : ($fam_HomePhone ?? '');
$sWorkPhone = $per_WorkPhone ?? '';
$sCellPhone = $per_CellPhone ?? '';
$sCountry = !empty($per_Country) ? $per_Country : ($fam_Country ?? '');
$sAddress1 = !empty($per_Address1) ? $per_Address1 : ($fam_Address1 ?? '');
$sAddress2 = !empty($per_Address2) ? $per_Address2 : ($fam_Address2 ?? '');
$sCity = !empty($per_City) ? $per_City : ($fam_City ?? '');
$sState = !empty($per_State) ? $per_State : ($fam_State ?? '');
$sZip = !empty($per_Zip) ? $per_Zip : ($fam_Zip ?? '');
$sEmail = !empty($per_Email) ? $per_Email : ($fam_Email ?? '');
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This person→family fallback block is now duplicated with similar logic in DirectoryReport.php. To reduce the chance of the two exports drifting (e.g., one adds Country fallback and the other doesn’t), consider centralizing the “resolved address/contact fields” logic in a shared helper/service method and using it in both places.

Copilot uses AI. Check for mistakes.
- Add PHP error checks (Fatal error, Parse error) to CSV export tests
- Verify at least one data row exists in export (validates fallback works)
- Add code comment noting similar logic in DirectoryReports.php for
  future consolidation consideration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Family and person addresses don't export to csv and some are not included in the Church Directory

1 participant