Repository: rubyforgood/human-essentials
Pull request #5142: 4946 partner profile export
Author: login: Benjamin-Couey
Created: 2025-04-03T18:43:45Z | Merged: 2025-04-22T23:02:24Z

<!--Read comments, before committing pull request read checklist again

# Checklist:

- I have performed a self-review of my own code,
- I have commented my code, particularly in hard-to-understand areas,
- I have made corresponding changes to the documentation,
- I have added tests that prove my fix is effective or that my feature works,
- New and existing unit tests pass locally with my changes ("bundle exec rake"),
- Title include "WIP" if work is in progress.
- I acknowledge that I will *not* force push my branch once reviews have started.

-->

Resolves #4946

### Description

Updated the `ExportPartnersCSVService` to export all of the `Partner::Profile` fields, filtered based on which `Partner.partials_to_show` the partner org selected.

The partials which are always shown (`agency_information` and `partner_settings`) will always have their fields included in the export.

Areas served was already implemented as described.

The database seed was updated to create partner profiles with dummy data in all of the fields if those partners are established (ready for approval, approved or require_recertification). The seed also only adds fields for optional partials which the partner's org has enabled.

To handle cases where `ExportPartnersCSVService` was called with no partners, `Organization` was updated to have a function that checks `partials_to_show` and `Partner`'s version of the function was udpated to refer to the `Organization` one. The same was done for the `ALL_PARTIALS` constant as `Organziation` already had a definition for it.

The existing `ExportPartnersCSVService` included some fields which were from optional partials (for example `primary_contact_name` from the `executive_director` partial). Similarly, some of the profile fields the database seed were already populating were from optional partials. These were not changed to be contingent on those partials being enabled for the sake of not changing the existing behavior and "hiding" data someone might have gotten used to seeing.

I considered formalizing the relationship between partials and profile fields (for example, a hash mapping partial names to field names). This idea was discarded because it wouldn't meaningfully simplify the export service, tests, or the partials themselves. A comment containing this information was added instead.

Because of how many fields there are in the `Partner::Profile`, the additions this PR makes are rather verbose and arguably hard to read. I did my best to organize them, but it is a notable tradeoff of this solution.

I considered entirely removing the `Partner.partials_to_show` function and `Partner.ALL_PARTIALS` constant. However, this would require refactoring a number of places that expect the `Partner` model to expose these which seemed outside the scope of this PR. I would recommend this change be made at some point for the sake of code cleanliness.

Currently, the `ExportPartnersCSVService` can only handle being passed a list of partners from one organization. Modifying it to handle partners from more than one organization seemed outside the scope of this PR. 

### Type of change

* New feature
* Documentation update

### How Has This Been Tested?

The export service was manually tested.

The existing `spec/services/exports/export_partners_csv_service_spec.rb` tests were modified to check for the newly added fields.

A test was added to verify that the `ExportPartnersCSVService` respects `partials_to_show`.

Two tests was added to verify that `ExportPartnersCSVService` handles being called with no partials.

The existing `spec/requests/partners_requests_spec.rb` tests were modified to check for the newly added fields.

Linked issue #4946: Partner Profile Export
# Summary
Add the ability to export the partner profiles
# Why?
Assists with making HE the 'golden copy' of information for banks, also for reporting to NDBN
# Details
Add an export for the partner profiles with (almost) all the fields, except area served, which is detailed below.
- For area served,   provide a field that lists the counties,  semi-colon-separated

Add a button for the export to the screen reached by signing in as org_admin1@example.com, then clicking "Partner Agencies" and "All Partners" in the left-hand menu.

The banks can configure which sections of the partner profile are used (see the organization information).  That configuration shall be taken into consideration for the export -- i.e. show the same sections.

# Criteria for completion
- [ ] behaviour as described
- [ ] tests to support
- [ ] update user guide to support
Linked issue comments: user: login: Benjamin-Couey
created_at: 2025-03-19T18:29:19Z
body: May I work on this one?
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-03-19T20:56:13Z
body: Please do!
author_association: COLLABORATOR
user: login: Benjamin-Couey
created_at: 2025-03-20T14:35:06Z
body: Two small questions.

The screen reached by signing in as an org admin, then clicking "Partner Agencies" and "All Partners" already has an "Export Partner Agencies" button. However, the CSV created by this button and the `ExportPartnersCSVService` it calls doesn't include any information from the profile aside from counties served. Should the functionality described by this issue be added on to this existing button and service(possibly with a toggle to select the current limited export vs the full export described in this issue), or should it be an entirely new and separate button and service?

Second, I'll need to create some dummy partner profile data for testing as while the db seed does create profiles for the partners, they aren't complete. Would you like me to update the seed to create complete profiles while I'm at it?
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-03-20T15:03:14Z
body: 1/  That's actually a pretty big question *g*.    I'm of two minds on it,  but since we already are putting information from the profile in the partner export,  it's not like we're making things simpler or faster by keeping them separate.

Let's put the profile information into the current one -- but put it *before* the counties served.

Hmmm.   In that case, the Counties served should also be disappeared if they aren't including that section.


2/  Could you reasonably only do complete on ones that are ready for approval, approved or require_recertification?   We wouldn't have complete ones for earlier statuses normally.    
author_association: COLLABORATOR
user: login: Benjamin-Couey
created_at: 2025-03-20T15:14:07Z
body: 1/ Sounds good, I'll modify the existing stuff.

2/ That would be doable yes. 
author_association: CONTRIBUTOR
user: login: Benjamin-Couey
created_at: 2025-03-21T17:25:44Z
body: Another point of clarification. `Partners::Profile` defines a list called `ignored_columns` which contains the names of a bunch of fields which currently aren't implemented in the forms of any partial. There are also a handful of fields (`application_data`, `distributor_type`, `status_in_diaper_base`) which aren't mentioned in `ignored_columns` but also don't show up in any view.

Am I correct in assuming the export should also ignore these fields?
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-03-21T23:15:02Z
body: Yup,  don't export the ignored columns.   We have a "Waiting for" with a time to go ahead and remove them in the proto-issues.
author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2025-04-21T00:18:21Z
body: This issue is marked as stale due to no activity within 30 days. If no further activity is detected within 7 days, it will be unassigned.
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-04-21T15:15:55Z
body: This is actively in the process of review-and-fix.

author_association: COLLABORATOR

Diff:
diff --git a/app/controllers/partners_controller.rb b/app/controllers/partners_controller.rb
index d94b35b0bb..696afe44c5 100644
--- a/app/controllers/partners_controller.rb
+++ b/app/controllers/partners_controller.rb
@@ -15,7 +15,7 @@ def index
 
     respond_to do |format|
       format.html
-      format.csv { send_data Exports::ExportPartnersCSVService.new(@partners.unscope(:includes)).generate_csv, filename: "Partners-#{Time.zone.today}.csv" }
+      format.csv { send_data Exports::ExportPartnersCSVService.new(@partners.unscope(:includes), current_organization).generate_csv, filename: "Partners-#{Time.zone.today}.csv" }
     end
   end
 
diff --git a/app/models/organization.rb b/app/models/organization.rb
index 5c70feaf7c..7acc1d9fac 100644
--- a/app/models/organization.rb
+++ b/app/models/organization.rb
@@ -168,6 +168,10 @@ def address_changed?
     street_changed? || city_changed? || state_changed? || zipcode_changed?
   end
 
+  def partials_to_show
+    partner_form_fields.presence || ALL_PARTIALS.map { |partial| partial[1] }
+  end
+
   def self.seed_items(organization = Organization.all)
     base_items = BaseItem.without_kit.map(&:to_h)
 
diff --git a/app/models/partner.rb b/app/models/partner.rb
index 0f0cdb12f0..017034d13e 100644
--- a/app/models/partner.rb
+++ b/app/models/partner.rb
@@ -66,18 +66,7 @@ class Partner < ApplicationRecord
     where(status: status.to_sym)
   }
 
-  ALL_PARTIALS = %w[
-    media_information
-    agency_stability
-    organizational_capacity
-    sources_of_funding
-    area_served
-    population_served
-    executive_director
-    pick_up_person
-    agency_distribution_information
-    attached_documents
-  ].freeze
+  ALL_PARTIALS = Organization::ALL_PARTIALS.map { |partial| partial[1] }.freeze
 
   # @return [String]
   def display_status
@@ -126,33 +115,8 @@ def self.import_csv(csv, organization_id)
     errors
   end
 
-  def contact_person
-    return @contact_person if @contact_person
-
-    @contact_person = {
-      name: profile.primary_contact_name,
-      email: profile.primary_contact_email,
-      phone: profile.primary_contact_phone ||
-             profile.primary_contact_mobile
-    }
-  end
-
-  def agency_info
-    return @agency_info if @agency_info
-
-    symbolic_agency_type = profile.agency_type&.to_sym
-    @agency_info = {
-      address: [profile.address1, profile.address2].select(&:present?).join(', '),
-      city: profile.city,
-      state: profile.state,
-      zip_code: profile.zip_code,
-      website: profile.website,
-      agency_type: (symbolic_agency_type == :other) ? "#{I18n.t symbolic_agency_type, scope: :partners_profile}: #{profile.other_agency_type}" : (I18n.t symbolic_agency_type, scope: :partners_profile)
-    }
-  end
-
   def partials_to_show
-    organization.partner_form_fields.presence || ALL_PARTIALS
+    organization.partials_to_show
   end
 
   def quantity_year_to_date
diff --git a/app/models/partners/profile.rb b/app/models/partners/profile.rb
index 9ae586d0d3..a62a26c9af 100644
--- a/app/models/partners/profile.rb
+++ b/app/models/partners/profile.rb
@@ -8,7 +8,6 @@
 #  address2                       :string
 #  agency_mission                 :text
 #  agency_type                    :string
-#  application_data               :text
 #  at_fpl_or_below                :integer
 #  case_management                :boolean
 #  city                           :string
@@ -16,7 +15,6 @@
 #  currently_provide_diapers      :boolean
 #  describe_storage_space         :text
 #  distribution_times             :string
-#  distributor_type               :string
 #  enable_child_based_requests    :boolean          default(TRUE), not null
 #  enable_individual_requests     :boolean          default(TRUE), not null
 #  enable_quantity_based_requests :boolean          default(TRUE), not null
@@ -144,7 +142,44 @@ class Profile < Base
     validate :has_at_least_one_request_setting
     validate :pick_up_email_addresses
 
+    # For the sake of documentation, here are the partials each field belongs to. In the order those
+    # partials appear in the actual form.
+    # agency_information -- this partial is always shown, contains the agency information AND the Program / Delivery Address sections of the form
+    #   agency_type, other_agency_type, agency_mission, address1, address2, city, state, zip_code,
+    #   program_address1, program_address2, program_city, program_state, program_zip_code
+    # media_information
+    #   website, facebook, twitter, instagram, no_social_media_presence
+    # agency_stability
+    #   founded, form_990, program_name, program_description, program_age, evidence_based, case_management,
+    #   essentials_use, receives_essentials_from_other, currently_provide_diapers
+    # organizational_capacity
+    #   client_capacity, storage_space, describe_storage_space
+    # sources_of_funding
+    #   sources_of_funding, sources_of_diapers, essentials_budget, essentials_funding_source
+    # area_served
+    #   has no associated Partners::Profile fields
+    # population_served
+    #   income_requirement_desc, income_verification, population_black, population_white,
+    #   population_hispanic, population_asian, population_american_indian, population_island,
+    #   population_multi_racial, population_other, zips_served, at_fpl_or_below, above_1_2_times_fpl
+    #   greater_2_times_fpl, poverty_unknown
+    # executive_director
+    #   executive_director_name, executive_director_phone, executive_director_email, primary_contact_name,
+    #   primary_contact_phone, primary_contact_mobile, primary_contact_email
+    # pick_up_person
+    #   pick_up_name, pick_up_phone, pick_up_email
+    # agency_distribution_information
+    #   distribution_times, new_client_times, more_docs_required
+    # attached_documents
+    #   has no associated Partners::Profile fields
+    # partner_settings -- this partial is always shown
+    #   enable_quantity_based_requests, enable_child_based_requests, enable_individual_requests
+
+    # These are columns which currently do not appear in any partial of the profile form.
+    # It is possible these will be removed in the future.
     self.ignored_columns += %w[
+      application_data
+      distributor_type
       evidence_based_description
       program_client_improvement
       incorporate_plan
diff --git a/app/services/exports/export_partners_csv_service.rb b/app/services/exports/export_partners_csv_service.rb
index 9425575d08..d06876c363 100644
--- a/app/services/exports/export_partners_csv_service.rb
+++ b/app/services/exports/export_partners_csv_service.rb
@@ -4,8 +4,12 @@ class ExportPartnersCSVService
     # to this service object; this is happening within the same request/response cycle, so it's already
     # in memory, so we can pass that collection in directly. Should this be moved to a background / async
     # job, we will need to pass in a collection of IDs instead.
-    def initialize(partners)
+    def initialize(partners, organization)
       @partners = partners.includes(:profile)
+      # Assumes that all of the partners belong to the same organization. This is true for the time being
+      # and, were that to change, base_table would need to be reworked anyway to account for partners from
+      # different orgs having different partials enabled, and thus different columns in the CSV.
+      @partials_to_show = organization.partials_to_show
     end
 
     def generate_csv
@@ -19,28 +23,148 @@ def generate_csv
 
     attr_reader :partners
 
-    def headers
-      base_table.keys
-    end
-
     def base_table
-      {
+      table = {
         "Agency Name" => ->(partner) { partner.name },
         "Agency Email" => ->(partner) { partner.email },
-        "Agency Address" => ->(partner) { partner.agency_info[:address] },
-        "Agency City" => ->(partner) { partner.agency_info[:city] },
-        "Agency State" => ->(partner) { partner.agency_info[:state] },
-        "Agency Zip Code" => ->(partner) { partner.agency_info[:zip_code] },
-        "Agency Website" => ->(partner) { partner.agency_info[:website] },
-        "Agency Type" => ->(partner) { partner.agency_info[:agency_type] },
-        "Contact Name" => ->(partner) { partner.contact_person[:name] },
-        "Contact Phone" => ->(partner) { partner.contact_person[:phone] },
-        "Contact Email" => ->(partner) { partner.contact_person[:email] },
         "Notes" => ->(partner) { partner.notes },
-        "Counties Served" => ->(partner) { county_list_by_regions[partner.id] || "" },
-        "Providing Diapers" => ->(partner) { diaper_statuses[partner.id] },
-        "Providing Period Supplies" => ->(partner) { period_supplies_statuses[partner.id] }
+        "Agency Type" => ->(partner) { I18n.t(partner.profile.agency_type, scope: :partners_profile) }, # Columns from the agency_information partial
+        "Other Agency Type" => ->(partner) { partner.profile.other_agency_type },
+        "Agency Mission" => ->(partner) { partner.profile.agency_mission },
+        "Agency Address" => ->(partner) {
+          (partner.profile.address1.blank? || partner.profile.address2.blank?) ?
+          "" : "#{partner.profile.address1}, #{partner.profile.address2}"
+        },
+        "Agency City" => ->(partner) { partner.profile.city },
+        "Agency State" => ->(partner) { partner.profile.state },
+        "Agency Zip Code" => ->(partner) { partner.profile.zip_code },
+        "Program/Delivery Address" => ->(partner) {
+          (partner.profile.program_address1.blank? || partner.profile.program_address2.blank?) ?
+          "" : "#{partner.profile.program_address1}, #{partner.profile.program_address2}"
+        },
+        "Program City" => ->(partner) { partner.profile.program_city },
+        "Program State" => ->(partner) { partner.profile.program_state },
+        "Program Zip Code" => ->(partner) { partner.profile.program_zip_code }
       }
+
+      media_information_col(table)
+      agency_stability_col(table)
+      organizational_capacity_col(table)
+      sources_of_funding_col(table)
+      area_served_col(table)
+      population_served_col(table)
+      executive_director_col(table)
+      pick_up_person_col(table)
+      agency_distribution_information_col(table)
+
+      table["Quantity-based Requests"] = ->(partner) { partner.profile.enable_quantity_based_requests } # Columns from the partner_settings partial
+      table["Child-based Requests"] = ->(partner) { partner.profile.enable_child_based_requests }
+      table["Individual Requests"] = ->(partner) { partner.profile.enable_individual_requests }
+
+      table["Providing Diapers"] = ->(partner) { diaper_statuses[partner.id] }
+      table["Providing Period Supplies"] = ->(partner) { period_supplies_statuses[partner.id] }
+
+      table
+    end
+
+    def media_information_col(table)
+      if @partials_to_show.include? "media_information"
+        table["Agency Website"] = ->(partner) { partner.profile.website }
+        table["Facebook"] = ->(partner) { partner.profile.facebook }
+        table["Twitter"] = ->(partner) { partner.profile.twitter }
+        table["Instagram"] = ->(partner) { partner.profile.instagram }
+        table["No Social Media Presence"] = ->(partner) { partner.profile.no_social_media_presence }
+      end
+    end
+
+    def agency_stability_col(table)
+      if @partials_to_show.include? "agency_stability"
+        table["Year Founded"] = ->(partner) { partner.profile.founded }
+        table["Form 990 Filed"] = ->(partner) { partner.profile.form_990 }
+        table["Program Name"] = ->(partner) { partner.profile.program_name }
+        table["Program Description"] = ->(partner) { partner.profile.program_description }
+        table["Agency Age"] = ->(partner) { partner.profile.program_age }
+        table["Evidence Based"] = ->(partner) { partner.profile.evidence_based }
+        table["Case Management"] = ->(partner) { partner.profile.case_management }
+        table["How Are Essentials Used"] = ->(partner) { partner.profile.essentials_use }
+        table["Receive Essentials From Other Sources"] = ->(partner) { partner.profile.receives_essentials_from_other }
+        table["Currently Providing Diapers"] = ->(partner) { partner.profile.currently_provide_diapers }
+      end
+    end
+
+    def organizational_capacity_col(table)
+      if @partials_to_show.include? "organizational_capacity"
+        table["Client Capacity"] = ->(partner) { partner.profile.client_capacity }
+        table["Storage Space"] = ->(partner) { partner.profile.storage_space }
+        table["Storage Space Description"] = ->(partner) { partner.profile.describe_storage_space }
+      end
+    end
+
+    def sources_of_funding_col(table)
+      if @partials_to_show.include? "sources_of_funding"
+        table["Sources Of Funding"] = ->(partner) { partner.profile.sources_of_funding }
+        table["How do you currently obtain diapers?"] = ->(partner) { partner.profile.sources_of_diapers }
+        table["Essentials Budget"] = ->(partner) { partner.profile.essentials_budget }
+        table["Essentials Funding Source"] = ->(partner) { partner.profile.essentials_funding_source }
+      end
+    end
+
+    def area_served_col(table)
+      if @partials_to_show.include? "area_served"
+        table["Area Served"] = ->(partner) { county_list_by_regions[partner.id] || "" }
+      end
+    end
+
+    def population_served_col(table)
+      if @partials_to_show.include? "population_served"
+        table["Income Requirement"] = ->(partner) { partner.profile.income_requirement_desc }
+        table["Verify Income"] = ->(partner) { partner.profile.income_verification }
+        table["% African American"] = ->(partner) { partner.profile.population_black }
+        table["% Caucasian"] = ->(partner) { partner.profile.population_white }
+        table["% Hispanic"] = ->(partner) { partner.profile.population_hispanic }
+        table["% Asian"] = ->(partner) { partner.profile.population_asian }
+        table["% American Indian"] = ->(partner) { partner.profile.population_american_indian }
+        table["% Pacific Island"] = ->(partner) { partner.profile.population_island }
+        table["% Multi-racial"] = ->(partner) { partner.profile.population_multi_racial }
+        table["% Other"] = ->(partner) { partner.profile.population_other }
+        table["Zip Codes Served"] = ->(partner) { partner.profile.zips_served }
+        table["% At FPL or Below"] = ->(partner) { partner.profile.at_fpl_or_below }
+        table["% Above 1-2 times FPL"] = ->(partner) { partner.profile.above_1_2_times_fpl }
+        table["% Greater than 2 times FPL"] = ->(partner) { partner.profile.greater_2_times_fpl }
+        table["% Poverty Unknown"] = ->(partner) { partner.profile.poverty_unknown }
+      end
+    end
+
+    def executive_director_col(table)
+      if @partials_to_show.include? "executive_director"
+        table["Executive Director Name"] = ->(partner) { partner.profile.executive_director_name }
+        table["Executive Director Phone"] = ->(partner) { partner.profile.executive_director_phone }
+        table["Executive Director Email"] = ->(partner) { partner.profile.executive_director_email }
+        table["Primary Contact Name"] = ->(partner) { partner.profile.primary_contact_name }
+        table["Primary Contact Phone"] = ->(partner) { partner.profile.primary_contact_phone }
+        table["Primary Contact Cell"] = ->(partner) { partner.profile.primary_contact_mobile }
+        table["Primary Contact Email"] = ->(partner) { partner.profile.primary_contact_email }
+      end
+    end
+
+    def pick_up_person_col(table)
+      if @partials_to_show.include? "pick_up_person"
+        table["Pick Up Person Name"] = ->(partner) { partner.profile.pick_up_name }
+        table["Pick Up Person Phone"] = ->(partner) { partner.profile.pick_up_phone }
+        table["Pick Up Person Email"] = ->(partner) { partner.profile.pick_up_email }
+      end
+    end
+
+    def agency_distribution_information_col(table)
+      if @partials_to_show.include? "agency_distribution_information"
+        table["Distribution Times"] = ->(partner) { partner.profile.distribution_times }
+        table["New Client Times"] = ->(partner) { partner.profile.new_client_times }
+        table["More Docs Required"] = ->(partner) { partner.profile.more_docs_required }
+      end
+    end
+
+    def headers
+      base_table.keys
     end
 
     def build_row_data(partner)
diff --git a/app/views/profiles/_show.html.erb b/app/views/profiles/_show.html.erb
index b8ca6c7033..cd2b31733d 100644
--- a/app/views/profiles/_show.html.erb
+++ b/app/views/profiles/_show.html.erb
@@ -55,7 +55,7 @@
       </p>
       <p>Program Name(s): <%= partner_profile.program_name %></p>
       <p>Program Description(s): <%= partner_profile.program_description %></p>
-      <p>Program Age: <%= partner_profile.program_age %></p>
+      <p>Agency Age: <%= partner_profile.program_age %></p>
       <p>Case Management: <%= humanize_boolean_3state(partner_profile.case_management) %></p>
       <p>Evidence Based: <%= humanize_boolean_3state(partner_profile.evidence_based) %></p>
       <p>How Are Essentials (e.g. diapers, period supplies) Used In Your Program? <%= partner_profile.essentials_use %></p>
@@ -146,7 +146,7 @@
     <% if partner_profile_fields.include?('sources_of_funding') || partner_profile_fields.empty? %>
       <h4 class='text-2xl underline'>Sources of Funding</h4>
       <p>Sources of Funding: <%= partner_profile.sources_of_funding %></p>
-      <p>Sources of Diapers: <%= partner_profile.sources_of_diapers %> </p>
+      <p>How do you currently obtain diapers? <%= partner_profile.sources_of_diapers %> </p>
       <p>Essentials Budget:<%= partner_profile.essentials_budget %></p>
       <p>Essentials Funding Source: <%= partner_profile.essentials_funding_source %></p>
       <br>
diff --git a/db/seeds.rb b/db/seeds.rb
index 98ca1cec42..90be3fd67d 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -282,28 +282,140 @@ def seed_random_item_with_name(organization, name)
     end
   end
 
-  Partners::Profile.create!({
+  # Base profile information all partners should have
+  # Includes fields in the agency_information, executive_director, and pick_up_person partial
+  # The counties and areas served by the partner are handled elsewere
+  profile = Partners::Profile.create!({
     essentials_bank_id: p.organization_id,
     partner_id: p.id,
     address1: Faker::Address.street_address,
-    address2: "",
+    address2: Faker::Address.street_address,
     city: Faker::Address.city,
-    state: Faker::Address.state_abbr,
-    zip_code: Faker::Address.zip,
-    website: Faker::Internet.domain_name,
-    zips_served: Faker::Address.zip,
-    executive_director_name: Faker::Name.name,
     executive_director_email: p.email,
+    executive_director_name: Faker::Name.name,
     executive_director_phone: Faker::PhoneNumber.phone_number,
-    primary_contact_name: Faker::Name.name,
+    pick_up_email: Faker::Internet.email,
+    pick_up_name: Faker::Name.name,
+    pick_up_phone: Faker::PhoneNumber.phone_number,
     primary_contact_email: Faker::Internet.email,
-    primary_contact_phone: Faker::PhoneNumber.phone_number,
     primary_contact_mobile: Faker::PhoneNumber.phone_number,
-    pick_up_name: Faker::Name.name,
-    pick_up_email: Faker::Internet.email,
-    pick_up_phone: Faker::PhoneNumber.phone_number
+    primary_contact_name: Faker::Name.name,
+    primary_contact_phone: Faker::PhoneNumber.phone_number,
+    state: Faker::Address.state_abbr,
+    website: Faker::Internet.domain_name,
+    zip_code: Faker::Address.zip,
+    zips_served: Faker::Address.zip,
   })
 
+  # Optional information that only established partners (ready for approval, approved or require_recertification)
+  # would have
+  # Also only add information that corresponds to the partner_form_fields the org has chosen
+  if [ "awaiting_review", "approved", "recertification_required" ].include? p.status
+    agency_type = Partners::Profile::agency_types.values.sample
+    # The agency_information and partner_settings partials are always shown
+    profile.update(
+      agency_mission: Faker::Lorem.paragraph(sentence_count: 2),
+      agency_type: agency_type,
+      enable_child_based_requests: true,
+      enable_individual_requests: true,
+      enable_quantity_based_requests: true,
+      name: p.name,
+      other_agency_type: (agency_type == "OTHER") ? Faker::Lorem.word : nil,
+      program_address1: Faker::Address.street_address,
+      program_address2: Faker::Address.street_address,
+      program_city: Faker::Address.city,
+      program_state: Faker::Address.state_abbr,
+      program_zip_code: Faker::Address.zip,
+    )
+
+    if p.partials_to_show.include? "media_information"
+      profile.update(
+        facebook: Faker::Internet.url(host: 'facebook.com'),
+        instagram: Faker::Internet.url(host: 'instagram.com'),
+        no_social_media_presence: false,
+        twitter: Faker::Internet.url(host: 'twitter.com'),
+      )
+    end
+
+    if p.partials_to_show.include? "agency_stability"
+      founded_year = Faker::Date.between(from: 50.years.ago, to: Date.today).year
+      profile.update(
+        case_management: true,
+        currently_provide_diapers: true,
+        essentials_use: Faker::Lorem.paragraph(sentence_count: 2),
+        evidence_based: true,
+        form_990: true,
+        founded: founded_year,
+        program_age: Date.today.year - founded_year,
+        program_description: Faker::Lorem.paragraph(sentence_count: 2),
+        program_name: Faker::Company.name,
+        receives_essentials_from_other: Faker::Lorem.sentence,
+      )
+    end
+  
+    if p.partials_to_show.include? "organizational_capacity"
+      profile.update(
+        client_capacity: Faker::Lorem.sentence,
+        describe_storage_space: Faker::Lorem.paragraph(sentence_count: 2),
+        storage_space: true,
+      )
+    end
+
+    if p.partials_to_show.include? "sources_of_funding"
+      profile.update(
+        essentials_budget: Faker::Lorem.sentence,
+        essentials_funding_source: Faker::Lorem.sentence,
+        sources_of_diapers: Faker::Lorem.sentence,
+        sources_of_funding: Faker::Lorem.sentence,
+      )
+    end
+
+    if p.partials_to_show.include? "population_served"
+
+      def calculate_array_of_percentages( num_entries )
+        percentages = []
+        remaining_percentage = 100
+        share_ceiling = 100 / num_entries
+        (num_entries - 1).times do
+          percentage = Faker::Number.within(range: 1..share_ceiling)
+          remaining_percentage -= percentage
+          percentages.append( percentage )
+        end
+        percentages.append( remaining_percentage )
+        return percentages
+      end
+
+      pop_percentages = calculate_array_of_percentages(8) # 8 population fields
+      poverty_percentages = calculate_array_of_percentages(4) # 4 poverty fields
+
+      profile.update(
+        above_1_2_times_fpl: poverty_percentages[0],
+        at_fpl_or_below: poverty_percentages[1],
+        greater_2_times_fpl: poverty_percentages[2],
+        income_requirement_desc: true,
+        income_verification: true,
+        population_american_indian: pop_percentages[0],
+        population_asian: pop_percentages[1],
+        population_black: pop_percentages[2],
+        population_hispanic: pop_percentages[3],
+        population_island: pop_percentages[4],
+        population_multi_racial: pop_percentages[5],
+        population_other: pop_percentages[6],
+        population_white: pop_percentages[7],
+        poverty_unknown: poverty_percentages[3],
+        zips_served: Faker::Address.zip_code,
+      )
+    end
+
+    if p.partials_to_show.include? "agency_distribution_information"
+      profile.update(
+        distribution_times: Faker::Lorem.sentence,
+        more_docs_required: Faker::Lorem.sentence,
+        new_client_times: Faker::Lorem.sentence,
+      )
+    end
+  end
+
   user = ::User.create!(
     name: Faker::Name.name,
     password: "password!",
diff --git a/docs/user_guide/bank/exports.md b/docs/user_guide/bank/exports.md
index 28fe4415c1..2f43a24e7b 100644
--- a/docs/user_guide/bank/exports.md
+++ b/docs/user_guide/bank/exports.md
@@ -190,7 +190,9 @@ For each filtered Item, the export includes:
 - Quantity (across your entire bank)
 
 ## Partners
-The partners export contains high level information about the partner.  It does not contain the information in the partner profile.
+The partners export contains high level information about the partner and information from the partner's profile that matches the sections of the partner profile form you have enabled.
+
+A full, detailed list of the fields in the partner profile can be found ["here"](pm_partner_profiles.md)
 
 ### Navigating to export partners
 Click "Partner Agencies", then "All Partners" in the left-hand menu.  Then click "Export Partner Agencies"
@@ -207,19 +209,99 @@ You can export different groups of partners by clicking the partner filters whic
 - Active
 
 ### Partner Export contents
-For each partner in the filtered list:
+For each partner in the filtered list the following fields will be exported:
 - Agency Name,
 - Agency Email,
+- Notes
+- Agency Type,
+- Other Agency Type,
+- Agency Mission,
 - Agency Address,
 - Agency City,
 - Agency State,
 - Agency Zip Code,
+- Program/Delivery Address,
+- Program City,
+- Program State,
+- Program Zip Code,
+
+The following fields will also be exported, at the end of the table
+- Quantity-based Requests,
+- Child-based Requests,
+- Individual Requests,
+- Providing Diapers,
+- Providing Period Supplies
+
+Optionally, the export will also include the following fields from the Partner Profile if the associated section of the form is enabled.
+
+Media Information
 - Agency Website,
-- Agency Type,
-- Contact Name,
-- Contact Phone,
-- Contact Email,
-- Notes
+- Facebook,
+- Twitter,
+- Instagram,
+- No Social Media Presence
+
+Agency Stability
+- Year Founded,
+- Form 990 Filed,
+- Program Name,
+- Program Description,
+- Agency Age,
+- Evidence Based,
+- Case Management,
+- How Are Essentials Used,
+- Receive Essentials From Other Sources,
+- Currently Providing Diapers
+
+Organization Capacity
+- Client Capacity,
+- Storage Space,
+- Storage Space Description
+
+Sources of Funding
+- Sources Of Funding,
+- How do you currently obtain diapers?,
+- Essentials Budget,
+- Essentials Funding Source
+
+Area Served
+- Sorted list of served counties
+
+Population Served
+- Income Requirement,
+- Verify Income,
+- % African American,
+- % Caucasian,
+- % Hispanic,
+- % Asian,
+- % American Indian,
+- % Pacific Island,
+- % Multi-racial,
+- % Other,
+- Zip Codes Served,
+- % At FPL or Below,
+- % Above 1-2 times FPL,
+- % Greater than 2 times FPL,
+- % Poverty Unknown
+
+Executive Director
+- Executive Director Name,
+- Executive Director Phone,
+- Executive Director Email,
+- Primary Contact Name,
+- Primary Contact Phone,
+- Primary Contact Cell,
+- Primary Contact Email
+
+Pick Up Person
+- Pick Up Person Name,
+- Pick Up Person Phone,
+- Pick Up Person Email
+
+Agency Distribution Information
+- Distribution Times,
+- New Client Times,
+- More Docs Required
 
 ## Product Drives
 ### Navigating to export Product Drives
diff --git a/spec/factories/partners/profiles.rb b/spec/factories/partners/profiles.rb
index 7b2e3f3500..f9d3e23c0c 100644
--- a/spec/factories/partners/profiles.rb
+++ b/spec/factories/partners/profiles.rb
@@ -8,7 +8,6 @@
 #  address2                       :string
 #  agency_mission                 :text
 #  agency_type                    :string
-#  application_data               :text
 #  at_fpl_or_below                :integer
 #  case_management                :boolean
 #  city                           :string
@@ -16,7 +15,6 @@
 #  currently_provide_diapers      :boolean
 #  describe_storage_space         :text
 #  distribution_times             :string
-#  distributor_type               :string
 #  enable_child_based_requests    :boolean          default(TRUE), not null
 #  enable_individual_requests     :boolean          default(TRUE), not null
 #  enable_quantity_based_requests :boolean          default(TRUE), not null
diff --git a/spec/models/partners/profile_spec.rb b/spec/models/partners/profile_spec.rb
index 80a6cb0c05..e176717277 100644
--- a/spec/models/partners/profile_spec.rb
+++ b/spec/models/partners/profile_spec.rb
@@ -8,7 +8,6 @@
 #  address2                       :string
 #  agency_mission                 :text
 #  agency_type                    :string
-#  application_data               :text
 #  at_fpl_or_below                :integer
 #  case_management                :boolean
 #  city                           :string
@@ -16,7 +15,6 @@
 #  currently_provide_diapers      :boolean
 #  describe_storage_space         :text
 #  distribution_times             :string
-#  distributor_type               :string
 #  enable_child_based_requests    :boolean          default(TRUE), not null
 #  enable_individual_requests     :boolean          default(TRUE), not null
 #  enable_quantity_based_requests :boolean          default(TRUE), not null
diff --git a/spec/requests/partners_requests_spec.rb b/spec/requests/partners_requests_spec.rb
index 2c849f6abb..3f9d07ce07 100644
--- a/spec/requests/partners_requests_spec.rb
+++ b/spec/requests/partners_requests_spec.rb
@@ -1,5 +1,6 @@
 RSpec.describe "Partners", type: :request do
-  let(:organization) { create(:organization) }
+  # Specify partner_form_fields for the sake of brevity in the csv output of GET #index.
+  let(:organization) { create(:organization, partner_form_fields: ["media_information"]) }
   let(:user) { create(:user, organization: organization) }
 
   before do
@@ -26,60 +27,91 @@
       let(:response_format) { 'csv' }
 
       let!(:partner) do
-        create(:partner, name:, email:, status: :approved, organization:, notes:, without_profile: true)
+        create(:partner, name: "Leslie Sue", email: "leslie@sue.com", status: :approved, organization:, notes: "Some notes", without_profile: true)
       end
       let!(:profile) do
         create(:partner_profile,
           partner: partner,
-          primary_contact_name: contact_name,
-          primary_contact_email: contact_email,
-          primary_contact_phone: contact_phone,
-          address1: agency_address1,
-          address2: agency_address2,
-          city: agency_city,
-          state: agency_state,
-          zip_code: agency_zipcode,
-          website: agency_website,
-          agency_type: agency_type,
-          other_agency_type: other_agency_type)
-      end
-      let(:name) { "Leslie Sue" }
-      let(:email) { "leslie@sue.com" }
-      let(:contact_name) { "Jon Ralfeo" }
-      let(:contact_email) { "jon@entertainment720.com" }
-      let(:contact_phone) { "1231231234" }
-      let(:agency_address1) { "4744 McDermott Mountain" }
-      let(:agency_address2) { "333 Never land street" }
-      let(:agency_city) { "Lake Shoshana" }
-      let(:agency_state) { "ND" }
-      let(:agency_zipcode) { "09980-7010" }
-      let(:agency_website) { "bosco.example" }
-      let(:agency_type) { :other }
-      let(:notes) { "Some notes" }
-      let(:other_agency_type) { "Another Agency Name" }
-      let(:providing_diapers) { {value: "N", index: 13} }
-      let(:providing_period_supplies) { {value: "N", index: 14} }
-
-      let(:response_format) { 'csv' }
-      let(:expected_headers) do
+          agency_type: :other, # Columns from the agency_information partial
+          other_agency_type: "Another Agency Name",
+          agency_mission: "agency_mission",
+          address1: "4744 McDermott Mountain",
+          address2: "333 Never land street",
+          city: "Lake Shoshana",
+          state: "ND",
+          zip_code: "09980-7010",
+          program_address1: "program_address1",
+          program_address2: "program_address2",
+          program_city: "program_city",
+          program_state: "program_state",
+          program_zip_code: 12345,
+          website: "bosco.example", # Columns from the media_information partial
+          facebook: "facebook",
+          twitter: "twitter",
+          instagram: "instagram",
+          no_social_media_presence: false,
+          enable_child_based_requests: true, # Columns from the partner_settings partial
+          enable_individual_requests: true,
+          enable_quantity_based_requests: true)
+      end
+
+      let(:expected_headers) {
         [
-          "Agency Name",
+          "Agency Name", # Technically not part of the agency_information partial, but comes at the start of the export
           "Agency Email",
+          "Notes",
+          "Agency Type", # Columns from the agency_information partial
+          "Other Agency Type",
+          "Agency Mission",
           "Agency Address",
           "Agency City",
           "Agency State",
           "Agency Zip Code",
-          "Agency Website",
-          "Agency Type",
-          "Contact Name",
-          "Contact Phone",
-          "Contact Email",
-          "Notes",
-          "Counties Served",
-          "Providing Diapers",
+          "Program/Delivery Address",
+          "Program City",
+          "Program State",
+          "Program Zip Code",
+          "Agency Website", # Columns from the media_information partial
+          "Facebook",
+          "Twitter",
+          "Instagram",
+          "No Social Media Presence",
+          "Quantity-based Requests", # Columns from the agency_information partial
+          "Child-based Requests",
+          "Individual Requests",
+          "Providing Diapers", # Technically not part of the partner_settings partial, but comes at the end of the export
           "Providing Period Supplies"
-      ]
-      end
+        ]
+      }
+
+      let(:expected_values) {
+        [
+          "Leslie Sue", # Technically not part of the agency_information partial, but comes at the start of the export
+          "leslie@sue.com",
+          "Some notes",
+          I18n.t("partners_profile.other"), # Columns from the agency_information partial
+          "Another Agency Name",
+          "agency_mission",
+          "4744 McDermott Mountain, 333 Never land street",
+          "Lake Shoshana",
+          "ND",
+          "09980-7010",
+          "program_address1, program_address2",
+          "program_city",
+          "program_state",
+          "12345",
+          "bosco.example", # Columns from the media_information partial
+          "facebook",
+          "twitter",
+          "instagram",
+          "false",
+          "true", # Columns from the partner_settings partial
+          "true",
+          "true",
+          "N", # Technically not part of the partner_settings partial, but comes at the end of the export
+          "N"
+        ]
+      }
 
       it { is_expected.to be_successful }
       it "returns the expected headers" do
@@ -91,29 +123,46 @@
       end
 
       context "with missing partner info" do
-        let(:name) { "Leslie" }
-        let(:email) { "leslie@humanessentials.com" }
-        let(:contact_name) { nil }
-        let(:contact_email) { nil }
-        let(:contact_phone) { nil }
-        let(:agency_address1) { nil }
-        let(:agency_address2) { nil }
-        let(:agency_city) { nil }
-        let(:agency_state) { nil }
-        let(:agency_zipcode) { nil }
-        let(:agency_website) { nil }
-        let(:agency_type) { nil }
-        let(:notes) { nil }
-        let(:other_agency_type) { nil }
-
         it "returns a CSV with correct data" do
-          get partners_path(partner, format: response_format)
+          partner.update(profile: create(
+            :partner_profile,
+            website: nil,
+            primary_contact_name: nil,
+            primary_contact_email: nil
+          ))
+
+          # The agency_information and settings sections contain information stored on the partner and not the
+          # profile, so they won't be completely empty
+          expected_values = [
+            "Leslie Sue",
+            "leslie@sue.com",
+            "Some notes",
+            "", # Columns from the agency_information partial
+            "",
+            "",
+            "",
+            "",
+            "",
+            "",
+            "",
+            "",
+            "",
+            "",
+            "", # Columns from the media_information partial
+            "",
+            "",
+            "",
+            "",
+            "true", # Columns from the partner_settings partial
+            "true",
+            "true",
+            "N",
+            "N"
+          ]
 
+          get partners_path(partner, format: response_format)
           csv = CSV.parse(response.body)
-
-          expect(csv[1]).to eq(
-            ["Leslie", "leslie@humanessentials.com", "", "", "", "", "", "", "", "", "", "", "", "N", "N"]
-          )
+          expect(csv[1]).to eq(expected_values)
         end
       end
 
@@ -122,39 +171,24 @@
 
         csv = CSV.parse(response.body)
 
-        expect(csv[1]).to eq(
-          [
-            "Leslie Sue",
-            "leslie@sue.com",
-            "4744 McDermott Mountain, 333 Never land street",
-            "Lake Shoshana",
-            "ND",
-            "09980-7010",
-            "bosco.example",
-            "Other: Another Agency Name",
-            "Jon Ralfeo",
-            "1231231234",
-            "jon@entertainment720.com",
-            "Some notes",
-            "",
-            "N",
-            "N"
-          ]
-        )
+        expect(csv[1]).to eq(expected_values)
       end
 
       it "returns only active partners by default" do
         partner.update(status: :deactivated)
 
         get partners_path(partner, format: response_format)
-
         csv = CSV.parse(response.body)
-
         # Expect no parner rows in csv
+        expect(csv[0]).to eq(expected_headers)
         expect(csv[1]).to eq(nil)
       end
 
       context "with served counties" do
+        before do
+          organization.update(partner_form_fields: organization.partner_form_fields += ["area_served"])
+        end
+
         it "returns them in correct order" do
           county_1 = create(:county, name: "High County, Maine", region: "Maine")
           county_2 = create(:county, name: "laRue County, Louisiana", region: "Louisiana")
@@ -167,47 +201,40 @@
 
           csv = CSV.parse(response.body, headers: true)
 
-          expect(csv[0]["Counties Served"]).to eq("laRue County, Louisiana; Ste. Anne County, Louisiana; High County, Maine")
+          expect(csv[0]["Area Served"]).to eq("laRue County, Louisiana; Ste. Anne County, Louisiana; High County, Maine")
         end
       end
 
       context "with multiple partners do" do
         let!(:partner_2) do
-          create(:partner, name: name_2, email: email_2, status: :invited, organization:, notes: notes_2, without_profile: true)
+          create(:partner, name: "Jane Doe", email: "jane@doe.com", status: :invited, organization:, notes: "Some notes", without_profile: true)
         end
         let!(:profile_2) do
           create(:partner_profile,
             partner: partner_2,
-            primary_contact_name: contact_name_2,
-            primary_contact_email: contact_email_2,
-            primary_contact_phone: contact_phone_2,
-            address1: agency_address1_2,
-            address2: agency_address2_2,
-            city: agency_city_2,
-            state: agency_state_2,
-            zip_code: agency_zipcode_2,
-            website: agency_website_2,
-            agency_type: agency_type_2,
-            other_agency_type: other_agency_type_2)
+            agency_type: :other, # Columns from the agency_information partial
+            other_agency_type: "Another Agency Name",
+            agency_mission: "agency_mission_2",
+            address1: "4744 McDermott Mountain",
+            address2: "333 Never land street",
+            city: "Lake Shoshana",
+            state: "ND",
+            zip_code: "09980-7010",
+            program_address1: "program_address1_2",
+            program_address2: "program_address2_2",
+            program_city: "program_city_2",
+            program_state: "program_state_2",
+            program_zip_code: 12345,
+            website: "bosco.example", # Columns from the media_information partial
+            facebook: "facebook_2",
+            twitter: "twitter_2",
+            instagram: "instagram_2",
+            no_social_media_presence: false,
+            enable_child_based_requests: true, # Columns from the partner_settings partial
+            enable_individual_requests: true,
+            enable_quantity_based_requests: true)
         end
 
-        let(:name_2) { "Jane Doe" }
-        let(:email_2) { "jane@doe.com" }
-        let(:contact_name_2) { "Fakey McFakePerson" }
-        let(:contact_email_2) { "fakey@gmail.com" }
-        let(:contact_phone_2) { "1234567890" }
-        let(:agency_address1_2) { "123 Main St" }
-        let(:agency_address2_2) { "C.O. box 678" }
-        let(:agency_city_2) { "Paris" }
-        let(:agency_state_2) { "TX" }
-        let(:agency_zipcode_2) { "30234-0000" }
-        let(:agency_website_2) { "human.example" }
-        let(:agency_type_2) { :other }
-        let(:notes_2) { "Some notes 2" }
-        let(:other_agency_type_2) { "Fake Agency Name" }
-        let(:providing_diapers_2) { {value: "N", index: 13} }
-        let(:providing_period_supplies_2) { {value: "N", index: 14} }
-
         it "orders partners alphaetically" do
           get partners_path(partner, format: response_format)
 
@@ -217,17 +244,26 @@
             [
               "Jane Doe",
               "jane@doe.com",
-              "123 Main St, C.O. box 678",
-              "Paris",
-              "TX",
-              "30234-0000",
-              "human.example",
-              "Other: Fake Agency Name",
-              "Fakey McFakePerson",
-              "1234567890",
-              "fakey@gmail.com",
-              "Some notes 2",
-              "",
+              "Some notes",
+              I18n.t("partners_profile.other"), # Columns from the agency_information partial
+              "Another Agency Name",
+              "agency_mission_2",
+              "4744 McDermott Mountain, 333 Never land street",
+              "Lake Shoshana",
+              "ND",
+              "09980-7010",
+              "program_address1_2, program_address2_2",
+              "program_city_2",
+              "program_state_2",
+              "12345",
+              "bosco.example", # Columns from the media_information partial
+              "facebook_2",
+              "twitter_2",
+              "instagram_2",
+              "false",
+              "true", # Columns from the partner_settings partial
+              "true",
+              "true",
               "N",
               "N"
             ]
diff --git a/spec/services/exports/export_partners_csv_service_spec.rb b/spec/services/exports/export_partners_csv_service_spec.rb
index fa1ca7a0dd..48af49d818 100644
--- a/spec/services/exports/export_partners_csv_service_spec.rb
+++ b/spec/services/exports/export_partners_csv_service_spec.rb
@@ -1,91 +1,363 @@
 RSpec.describe Exports::ExportPartnersCSVService do
   describe "#generate_csv" do
-    subject { CSV.parse(described_class.new(partners).generate_csv) }
+    subject { CSV.parse(described_class.new(partners, organization).generate_csv) }
 
     let(:organization) { create(:organization) }
 
-    let!(:partner) { create(:partner, status: :approved, organization:, notes:, without_profile: true) }
+    let!(:partner) { create(:partner, name: "Jane Doe", email: "jane@doe.com", status: :approved, organization:, notes: "Some notes", without_profile: true) }
     let!(:profile) do
       create(:partner_profile,
         partner: partner,
-        primary_contact_name: contact_name,
-        primary_contact_email: contact_email,
-        primary_contact_phone: contact_phone,
-        address1: agency_address1,
-        address2: agency_address2,
-        city: agency_city,
-        state: agency_state,
-        zip_code: agency_zipcode,
-        website: agency_website,
-        agency_type: agency_type,
-        other_agency_type: other_agency_type)
+        agency_type: :other, # Columns from the agency_information partial
+        other_agency_type: "Another Agency Name",
+        agency_mission: "agency_mission",
+        address1: "4744 McDermott Mountain",
+        address2: "333 Never land street",
+        city: "Lake Shoshana",
+        state: "ND",
+        zip_code: "09980-7010",
+        program_address1: "program_address1",
+        program_address2: "program_address2",
+        program_city: "program_city",
+        program_state: "program_state",
+        program_zip_code: 12345,
+        website: "bosco.example", # Columns from the media_information partial
+        facebook: "facebook",
+        twitter: "twitter",
+        instagram: "instagram",
+        no_social_media_presence: false,
+        founded: 2020, # Columns from the agency_stability partial
+        form_990: true,
+        program_name: "program_name",
+        program_description: "program_description",
+        program_age: 5,
+        evidence_based: true,
+        case_management: true,
+        essentials_use: "essentials_use",
+        receives_essentials_from_other: "receives_essentials_from_other",
+        currently_provide_diapers: true,
+        client_capacity: "client_capacity", # Columns from the organizational_capacitypartial
+        storage_space: true,
+        describe_storage_space: "describe_storage_space",
+        sources_of_funding: "sources_of_funding", # Columns from the sources_of_funding partial
+        sources_of_diapers: "sources_of_diapers",
+        essentials_budget: "essentials_budget",
+        essentials_funding_source: "essentials_funding_source",
+        income_requirement_desc: true, # Columns from the population_served partial
+        income_verification: true,
+        population_black: 10,
+        population_white: 10,
+        population_hispanic: 10,
+        population_asian: 10,
+        population_american_indian: 10,
+        population_island: 10,
+        population_multi_racial: 10,
+        population_other: 30,
+        zips_served: "zips_served",
+        at_fpl_or_below: 25,
+        above_1_2_times_fpl: 25,
+        greater_2_times_fpl: 25,
+        poverty_unknown: 25,
+        executive_director_name: "executive_director_name", # Columns from the executive_director partial
+        executive_director_phone: "executive_director_phone",
+        executive_director_email: "executive_director_email",
+        primary_contact_name: "Jon Ralfeo",
+        primary_contact_phone: "1231231234",
+        primary_contact_mobile: "4564564567",
+        primary_contact_email: "jon@entertainment720.com",
+        pick_up_name: "pick_up_name", # Columns from the pick_up_personpartial
+        pick_up_phone: "pick_up_phone",
+        pick_up_email: "pick_up_email@email.com",
+        distribution_times: "distribution_times", # Columns from the agency_distribution_information partial
+        new_client_times: "new_client_times",
+        more_docs_required: "more_docs_required",
+        enable_child_based_requests: true, # Columns from the partner_settings partial
+        enable_individual_requests: true,
+        enable_quantity_based_requests: true)
     end
-    let(:contact_name) { "Jon Ralfeo" }
-    let(:contact_email) { "jon@entertainment720.com" }
-    let(:contact_phone) { "1231231234" }
-    let(:agency_address1) { "4744 McDermott Mountain" }
-    let(:agency_address2) { "333 Never land street" }
-    let(:agency_city) { "Lake Shoshana" }
-    let(:agency_state) { "ND" }
-    let(:agency_zipcode) { "09980-7010" }
-    let(:agency_website) { "bosco.example" }
-    let(:agency_type) { :other }
-    let(:notes) { "Some notes" }
-    let(:other_agency_type) { "Another Agency Name" }
-    let(:providing_diapers) { {value: "N", index: 13} }
-    let(:providing_period_supplies) { {value: "N", index: 14} }
+
+    let(:county_1) { create(:county, name: "High County, Maine", region: "Maine") } # Information for the area_served parital
+    let(:county_2) { create(:county, name: "laRue County, Louisiana", region: "Louisiana") }
+    let(:county_3) { create(:county, name: "Ste. Anne County, Louisiana", region: "Louisiana") }
+    let!(:served_area_1) { create(:partners_served_area, partner_profile: profile, county: county_1, client_share: 50) }
+    let!(:served_area_2) { create(:partners_served_area, partner_profile: profile, county: county_2, client_share: 40) }
+    let!(:served_area_3) { create(:partners_served_area, partner_profile: profile, county: county_3, client_share: 10) }
 
     let(:partners) { Partner.all }
 
+    let(:optional_partials) {
+      [
+        :media_information,
+        :agency_stability,
+        :organizational_capacity,
+        :sources_of_funding,
+        :area_served,
+        :population_served,
+        :executive_director,
+        :pick_up_person,
+        :agency_distribution_information
+        ]
+    }
+
+    let(:partial_to_headers) {
+      {
+        agency_information: [
+          "Agency Name", # Technically not part of the agency_information partial, but comes at the start of the export
+          "Agency Email",
+          "Notes",
+          "Agency Type", # Columns from the agency_information partial
+          "Other Agency Type",
+          "Agency Mission",
+          "Agency Address",
+          "Agency City",
+          "Agency State",
+          "Agency Zip Code",
+          "Program/Delivery Address",
+          "Program City",
+          "Program State",
+          "Program Zip Code"
+        ],
+        media_information: [
+          "Agency Website",
+          "Facebook",
+          "Twitter",
+          "Instagram",
+          "No Social Media Presence"
+        ],
+        agency_stability: [
+          "Year Founded",
+          "Form 990 Filed",
+          "Program Name",
+          "Program Description",
+          "Agency Age",
+          "Evidence Based",
+          "Case Management",
+          "How Are Essentials Used",
+          "Receive Essentials From Other Sources",
+          "Currently Providing Diapers"
+        ],
+        organizational_capacity: [
+          "Client Capacity",
+          "Storage Space",
+          "Storage Space Description"
+        ],
+        sources_of_funding: [
+          "Sources Of Funding",
+          "How do you currently obtain diapers?",
+          "Essentials Budget",
+          "Essentials Funding Source"
+        ],
+        area_served: [
+          "Area Served"
+        ],
+        population_served: [
+          "Income Requirement",
+          "Verify Income",
+          "% African American",
+          "% Caucasian",
+          "% Hispanic",
+          "% Asian",
+          "% American Indian",
+          "% Pacific Island",
+          "% Multi-racial",
+          "% Other",
+          "Zip Codes Served",
+          "% At FPL or Below",
+          "% Above 1-2 times FPL",
+          "% Greater than 2 times FPL",
+          "% Poverty Unknown"
+        ],
+        executive_director: [
+          "Executive Director Name",
+          "Executive Director Phone",
+          "Executive Director Email",
+          "Primary Contact Name",
+          "Primary Contact Phone",
+          "Primary Contact Cell",
+          "Primary Contact Email"
+        ],
+        pick_up_person: [
+          "Pick Up Person Name",
+          "Pick Up Person Phone",
+          "Pick Up Person Email"
+        ],
+        agency_distribution_information: [
+          "Distribution Times",
+          "New Client Times",
+          "More Docs Required"
+        ],
+        partner_settings: [
+          "Quantity-based Requests", # Columns from the agency_information partial
+          "Child-based Requests",
+          "Individual Requests",
+          "Providing Diapers", # Technically not part of the partner_settings partial, but comes at the end of the export
+          "Providing Period Supplies"
+        ]
+      }
+    }
+
+    let(:partial_to_values) {
+      {
+        agency_information: [
+          "Jane Doe", # Technically not part of the agency_information partial, but come at the start of the export
+          "jane@doe.com",
+          "Some notes",
+          I18n.t("partners_profile.other"), # Columns from the agency_information partial
+          "Another Agency Name",
+          "agency_mission",
+          "4744 McDermott Mountain, 333 Never land street",
+          "Lake Shoshana",
+          "ND",
+          "09980-7010",
+          "program_address1, program_address2",
+          "program_city",
+          "program_state",
+          "12345"
+        ],
+        media_information: [
+          "bosco.example",
+          "facebook",
+          "twitter",
+          "instagram",
+          "false"
+        ],
+        agency_stability: [
+          "2020",
+          "true",
+          "program_name",
+          "program_description",
+          "5",
+          "true",
+          "true",
+          "essentials_use",
+          "receives_essentials_from_other",
+          "true"
+        ],
+        organizational_capacity: [
+          "client_capacity",
+          "true",
+          "describe_storage_space"
+        ],
+        sources_of_funding: [
+          "sources_of_funding",
+          "sources_of_diapers",
+          "essentials_budget",
+          "essentials_funding_source"
+        ],
+        area_served: [
+          # county ordering is a bit esoteric -- it is human alphabetical by county within region (region is state)
+          "laRue County, Louisiana; Ste. Anne County, Louisiana; High County, Maine"
+        ],
+        population_served: [
+          "true",
+          "true",
+          "10",
+          "10",
+          "10",
+          "10",
+          "10",
+          "10",
+          "10",
+          "30",
+          "zips_served",
+          "25",
+          "25",
+          "25",
+          "25"
+        ],
+        executive_director: [
+          "executive_director_name",
+          "executive_director_phone",
+          "executive_director_email",
+          "Jon Ralfeo",
+          "1231231234",
+          "4564564567",
+          "jon@entertainment720.com"
+        ],
+        pick_up_person: [
+          "pick_up_name",
+          "pick_up_phone",
+          "pick_up_email@email.com"
+        ],
+        agency_distribution_information: [
+          "distribution_times",
+          "new_client_times",
+          "more_docs_required"
+        ],
+        partner_settings: [
+          "true", # Columns from the agency_information partial
+          "true",
+          "true",
+          "N", # Technically not part of the partner_settings partial, but comes at the end of the export
+          "N"
+        ]
+      }
+    }
+
     it "should have the correct headers" do
-      expected_headers = [
-        "Agency Name",
-        "Agency Email",
-        "Agency Address",
-        "Agency City",
-        "Agency State",
-        "Agency Zip Code",
-        "Agency Website",
-        "Agency Type",
-        "Contact Name",
-        "Contact Phone",
-        "Contact Email",
-        "Notes",
-        "Counties Served",
-        "Providing Diapers",
-        "Providing Period Supplies"
-      ]
-
-      expect(subject[0]).to eq(expected_headers)
+      expect(subject[0]).to eq(partial_to_headers.values.flatten)
     end
 
     it "should have the expected info in the columns order" do
-      county_1 = create(:county, name: "High County, Maine", region: "Maine")
-      county_2 = create(:county, name: "laRue County, Louisiana", region: "Louisiana")
-      county_3 = create(:county, name: "Ste. Anne County, Louisiana", region: "Louisiana")
-      create(:partners_served_area, partner_profile: profile, county: county_1, client_share: 50)
-      create(:partners_served_area, partner_profile: profile, county: county_2, client_share: 40)
-      create(:partners_served_area, partner_profile: profile, county: county_3, client_share: 10)
-
-      # county ordering is a bit esoteric -- it is human alphabetical by county within region (region is state)
-      correctly_ordered_counties = "laRue County, Louisiana; Ste. Anne County, Louisiana; High County, Maine"
-      expect(subject[1]).to eq([
-        partner.name,
-        partner.email,
-        "#{agency_address1}, #{agency_address2}",
-        agency_city,
-        agency_state,
-        agency_zipcode,
-        agency_website,
-        "#{I18n.t "partners_profile.other"}: #{other_agency_type}",
-        contact_name,
-        contact_phone,
-        contact_email,
-        notes,
-        correctly_ordered_counties,
-        providing_diapers[:value],
-        providing_period_supplies[:value]
-      ])
+      expect(subject[1]).to eq(partial_to_values.values.flatten)
+    end
+
+    it "should handle a partner with missing profile info" do
+      # The partner_profile factory defaults to populating the website, primary_contact_name, and primary_contact_email fields
+      partners.first.update(profile: create(
+        :partner_profile,
+        website: nil,
+        primary_contact_name: nil,
+        primary_contact_email: nil
+      ))
+      expected_values = []
+      partial_to_values.keys.each do |partial|
+        # The agency_information and settings sections contain information stored on the partner and not the
+        # profile, so they won't be completely empty
+        expected_values += case partial
+        when :agency_information
+          ["Jane Doe", "jane@doe.com", "Some notes", "", "", "", "", "", "", "", "", "", "", ""]
+        when :partner_settings
+          [
+            "true",
+            "true",
+            "true",
+            "N",
+            "N"
+          ]
+        else
+          Array.new(partial_to_values[partial].count) { "" }
+        end
+      end
+      expect(subject[1]).to eq(expected_values)
+    end
+
+    it "should only export columns in profile sections the org has enabled" do
+      optional_partials.each do |partial|
+        organization.update(partner_form_fields: [partial])
+        partners.reload
+        limited_export = CSV.parse(described_class.new(partners, organization).generate_csv)
+        expect(limited_export[0]).to eq(partial_to_headers[:agency_information] + partial_to_headers[partial] + partial_to_headers[:partner_settings])
+        expect(limited_export[1]).to eq(partial_to_values[:agency_information] + partial_to_values[partial] + partial_to_values[:partner_settings])
+      end
+    end
+
+    context "when there are no partners" do
+      let(:partners) { Partner.none }
+      it "should have the correct headers and no other rows" do
+        expect(subject[0]).to eq(partial_to_headers.values.flatten)
+        expect(subject[1]).to eq(nil)
+      end
+
+      it "should only export columns in profile sections the org has enabled" do
+        optional_partials.each do |partial|
+          organization.update(partner_form_fields: [partial])
+          partners.reload
+          limited_export = CSV.parse(described_class.new(partners, organization).generate_csv)
+          expect(limited_export[0]).to eq(partial_to_headers[:agency_information] + partial_to_headers[partial] + partial_to_headers[:partner_settings])
+          expect(limited_export[1]).to eq(nil)
+        end
+      end
     end
 
     context "when partner has a distribution in the last 12 months" do
@@ -93,8 +365,6 @@
 
       shared_examples "providing_diapers check" do |scope|
         before do
-          providing_diapers[:value] = "Y"
-
           case scope
           when :disposable_diapers
             item = create(:item, reporting_category: :disposable_diapers)
@@ -106,7 +376,7 @@
         end
 
         it "should have Y as providing_diapers" do
-          expect(subject[1][providing_diapers[:index]]).to eq(providing_diapers[:value])
+          expect(subject[1][-2]).to eq("Y")
         end
       end
 
@@ -120,14 +390,12 @@
 
       context "with a period supplies item" do
         before do
-          providing_period_supplies[:value] = "Y"
-
-          item = create(:item, organization:, reporting_category: :tampons)
+          item = create(:item, reporting_category: :tampons)
           create(:line_item, item: item, itemizable: distribution)
         end
 
         it "should have Y as providing_period_supplies" do
-          expect(subject[1][providing_period_supplies[:index]]).to eq(providing_period_supplies[:value])
+          expect(subject[1][-1]).to eq("Y")
         end
       end
     end
@@ -145,11 +413,11 @@
       end
 
       it "should have N as providing_diapers" do
-        expect(subject[1][providing_diapers[:index]]).to eq(providing_diapers[:value])
+        expect(subject[1][-2]).to eq("N")
       end
 
       it "should have N as providing_period_supplies" do
-        expect(subject[1][providing_period_supplies[:index]]).to eq(providing_period_supplies[:value])
+        expect(subject[1][-1]).to eq("N")
       end
     end
   end


Reviews:
user: login: cielf
body: Hey @Benjamin-Couey -- I've taken a light stab at the functional testing and I've noticed one thing I'd like to change.   It looks to me like you've put all the mandatory fields first,  then the user-configured fields.  

Would it be reasonable to get  the fields in the same order as they are in the profile as seen by the banks?   (for example, the Child-based requests, etc  would be at the end)


state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-04-04T00:19:41Z
user: login: cielf
body: Hey @Benjamin-Couey 

It looks like we still have some crossed wires.   We're definitely going to need to do some communication to the banks when this goes out!

See attached --- I think it's self-explanatory, but if something's unclear,  or you think I'm just wrong, please don't hesitate to reach out.

[Partner export notes.pdf](https://github.com/user-attachments/files/19712047/Partner.export.notes.pdf)


state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-04-11T17:48:16Z
user: login: dorner
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-04-16T16:04:05Z
user: login: Benjamin-Couey
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T15:46:00Z
user: login: Benjamin-Couey
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T15:46:56Z
user: login: dorner
body: Thank you!
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-22T23:01:53Z

Review comments:
diff_hunk: @@ -24,23 +28,115 @@ def headers
     end
 
     def base_table
-      {
+      table = {
         "Agency Name" => ->(partner) { partner.name },
         "Agency Email" => ->(partner) { partner.email },
-        "Agency Address" => ->(partner) { partner.agency_info[:address] },
-        "Agency City" => ->(partner) { partner.agency_info[:city] },
-        "Agency State" => ->(partner) { partner.agency_info[:state] },
-        "Agency Zip Code" => ->(partner) { partner.agency_info[:zip_code] },
-        "Agency Website" => ->(partner) { partner.agency_info[:website] },
-        "Agency Type" => ->(partner) { partner.agency_info[:agency_type] },
-        "Contact Name" => ->(partner) { partner.contact_person[:name] },
-        "Contact Phone" => ->(partner) { partner.contact_person[:phone] },
-        "Contact Email" => ->(partner) { partner.contact_person[:email] },
         "Notes" => ->(partner) { partner.notes },
-        "Counties Served" => ->(partner) { county_list_by_regions[partner.id] || "" },
-        "Providing Diapers" => ->(partner) { diaper_statuses[partner.id] },
-        "Providing Period Supplies" => ->(partner) { period_supplies_statuses[partner.id] }
+        "Agency Type" => ->(partner) { I18n.t(partner.profile.agency_type, scope: :partners_profile) }, # Columns from the agency_information partial
+        "Other Agency Type" => ->(partner) { partner.profile.other_agency_type },
+        "Agency Mission" => ->(partner) { partner.profile.agency_mission },
+        "Agency Address" => ->(partner) {
+          (partner.profile.address1.blank? || partner.profile.address2.blank?) ?
+          "" : "#{partner.profile.address1}, #{partner.profile.address2}"
+        },
+        "Agency City" => ->(partner) { partner.profile.city },
+        "Agency State" => ->(partner) { partner.profile.state },
+        "Agency Zip Code" => ->(partner) { partner.profile.zip_code },
+        "Program/Delivery Address" => ->(partner) {
+          (partner.profile.program_address1.blank? || partner.profile.program_address2.blank?) ?
+          "" : "#{partner.profile.program_address1}, #{partner.profile.program_address2}"
+        },
+        "Program City" => ->(partner) { partner.profile.program_city },
+        "Program State" => ->(partner) { partner.profile.program_state },
+        "Program Zip Code" => ->(partner) { partner.profile.program_zip_code }
       }
+
+      if @partials_to_show.include? "media_information"
+        table["Agency Website"] = ->(partner) { partner.profile.website }
+        table["Facebook"] = ->(partner) { partner.profile.facebook }
+        table["Twitter"] = ->(partner) { partner.profile.twitter }
+        table["Instagram"] = ->(partner) { partner.profile.instagram }
+        table["No Social Media Presence"] = ->(partner) { partner.profile.no_social_media_presence }
+      end
+
+      if @partials_to_show.include? "agency_stability"
+        table["Year Founded"] = ->(partner) { partner.profile.founded }
+        table["Form 990 Filed"] = ->(partner) { partner.profile.form_990 }
+        table["Program Name"] = ->(partner) { partner.profile.program_name }
+        table["Program Description"] = ->(partner) { partner.profile.program_description }
+        table["Agency Age"] = ->(partner) { partner.profile.program_age }
+        table["Evidence Based"] = ->(partner) { partner.profile.evidence_based }
+        table["Case Management"] = ->(partner) { partner.profile.case_management }
+        table["How Are Essentials Used"] = ->(partner) { partner.profile.essentials_use }
+        table["Receive Essentials From Other Sources"] = ->(partner) { partner.profile.receives_essentials_from_other }
+        table["Currently Providing Diapers"] = ->(partner) { partner.profile.currently_provide_diapers }
+      end
+
+      if @partials_to_show.include? "organizational_capacity"
+        table["Client Capacity"] = ->(partner) { partner.profile.client_capacity }
+        table["Storage Space"] = ->(partner) { partner.profile.storage_space }
+        table["Storage Space Description"] = ->(partner) { partner.profile.describe_storage_space }
+      end
+
+      if @partials_to_show.include? "sources_of_funding"
+        table["Sources Of Funding"] = ->(partner) { partner.profile.sources_of_funding }
+        table["How do you currently obtain diapers?"] = ->(partner) { partner.profile.sources_of_diapers }
+        table["Essentials Budget"] = ->(partner) { partner.profile.essentials_budget }
+        table["Essentials Funding Source"] = ->(partner) { partner.profile.essentials_funding_source }
+      end
+
+      if @partials_to_show.include? "area_served"
+        table["Area Served"] = ->(partner) { county_list_by_regions[partner.id] || "" }
+      end
+
+      if @partials_to_show.include? "population_served"
+        table["Income Requirement"] = ->(partner) { partner.profile.income_requirement_desc }
+        table["Verify Income"] = ->(partner) { partner.profile.income_verification }
+        table["% African American"] = ->(partner) { partner.profile.population_black }
+        table["% Caucasian"] = ->(partner) { partner.profile.population_white }
+        table["% Hispanic"] = ->(partner) { partner.profile.population_hispanic }
+        table["% Asian"] = ->(partner) { partner.profile.population_asian }
+        table["% American Indian"] = ->(partner) { partner.profile.population_american_indian }
+        table["% Pacific Island"] = ->(partner) { partner.profile.population_island }
+        table["% Multi-racial"] = ->(partner) { partner.profile.population_multi_racial }
+        table["% Other"] = ->(partner) { partner.profile.population_other }
+        table["Zip Codes Served"] = ->(partner) { partner.profile.zips_served }
+        table["% At FPL or Below"] = ->(partner) { partner.profile.at_fpl_or_below }
+        table["% Above 1-2 times FPL"] = ->(partner) { partner.profile.above_1_2_times_fpl }
+        table["% Greater than 2 times FPL"] = ->(partner) { partner.profile.greater_2_times_fpl }
+        table["% Poverty Unknown"] = ->(partner) { partner.profile.poverty_unknown }
+      end
+
+      if @partials_to_show.include? "executive_director"
+        table["Executive Director Name"] = ->(partner) { partner.profile.executive_director_name }
+        table["Executive Director Phone"] = ->(partner) { partner.profile.executive_director_phone }
+        table["Executive Director Email"] = ->(partner) { partner.profile.executive_director_email }
+        table["Primary Contact Name"] = ->(partner) { partner.profile.primary_contact_name }
+        table["Primary Contact Phone"] = ->(partner) { partner.profile.primary_contact_phone }
+        table["Primary Contact Cell"] = ->(partner) { partner.profile.primary_contact_mobile }
+        table["Primary Contact Email"] = ->(partner) { partner.profile.primary_contact_email }
+      end
+
+      if @partials_to_show.include? "pick_up_person"
+        table["Pick Up Person Name"] = ->(partner) { partner.profile.pick_up_name }
+        table["Pick Up Person Phone"] = ->(partner) { partner.profile.pick_up_phone }
+        table["Pick Up Person Email"] = ->(partner) { partner.profile.pick_up_email }
+      end
+
+      if @partials_to_show.include? "agency_distribution_information"
+        table["Distribution Times"] = ->(partner) { partner.profile.distribution_times }
+        table["New Client Times"] = ->(partner) { partner.profile.new_client_times }
+        table["More Docs Required"] = ->(partner) { partner.profile.more_docs_required }
+      end
+
+      table["Quantity-based Requests"] = ->(partner) { partner.profile.enable_quantity_based_requests } # Columns from the partner_settings partial
+      table["Child-based Requests"] = ->(partner) { partner.profile.enable_child_based_requests }
+      table["Individual Requests"] = ->(partner) { partner.profile.enable_individual_requests }
+
+      table["Providing Diapers"] = ->(partner) { diaper_statuses[partner.id] }
+      table["Providing Period Supplies"] = ->(partner) { period_supplies_statuses[partner.id] }
+
+      table
path: app/services/exports/export_partners_csv_service.rb
user: login: dorner
body: Can we split this function up a bit? There are some pretty obvious places to do it. A 70+ line function makes me leery.
created_at: 2025-04-16T16:02:48Z
author_association: COLLABORATOR
diff_hunk: @@ -31,55 +32,112 @@
       let!(:profile) do
         create(:partner_profile,
           partner: partner,
-          primary_contact_name: contact_name,
-          primary_contact_email: contact_email,
-          primary_contact_phone: contact_phone,
+          agency_type: agency_type, # Columns from the agency_information partial
+          other_agency_type: other_agency_type,
+          agency_mission: agency_mission,
           address1: agency_address1,
           address2: agency_address2,
           city: agency_city,
           state: agency_state,
           zip_code: agency_zipcode,
-          website: agency_website,
-          agency_type: agency_type,
-          other_agency_type: other_agency_type)
+          program_address1: program_address1,
+          program_address2: program_address2,
+          program_city: program_city,
+          program_state: program_state,
+          program_zip_code: program_zip_code,
+          website: agency_website, # Columns from the media_information partial
+          facebook: facebook,
+          twitter: twitter,
+          instagram: instagram,
+          no_social_media_presence: no_social_media_presence,
+          enable_child_based_requests: enable_child_based_requests, # Columns from the partner_settings partial
+          enable_individual_requests: enable_individual_requests,
+          enable_quantity_based_requests: enable_quantity_based_requests)
       end
       let(:name) { "Leslie Sue" }
       let(:email) { "leslie@sue.com" }
-      let(:contact_name) { "Jon Ralfeo" }
-      let(:contact_email) { "jon@entertainment720.com" }
-      let(:contact_phone) { "1231231234" }
+      let(:notes) { "Some notes" }
+      let(:agency_type) { :other } # Columns from the agency_information partial
+      let(:other_agency_type) { "Another Agency Name" }
+      let(:agency_mission) { "agency_mission" }
       let(:agency_address1) { "4744 McDermott Mountain" }
       let(:agency_address2) { "333 Never land street" }
       let(:agency_city) { "Lake Shoshana" }
       let(:agency_state) { "ND" }
       let(:agency_zipcode) { "09980-7010" }
-      let(:agency_website) { "bosco.example" }
-      let(:agency_type) { :other }
-      let(:notes) { "Some notes" }
-      let(:other_agency_type) { "Another Agency Name" }
-      let(:providing_diapers) { {value: "N", index: 13} }
-      let(:providing_period_supplies) { {value: "N", index: 14} }
-
-      let(:response_format) { 'csv' }
-      let(:expected_headers) do
+      let(:program_address1) { "program_address1" }
+      let(:program_address2) { "program_address2" }
+      let(:program_city) { "program_city" }
+      let(:program_state) { "program_state" }
+      let(:program_zip_code) { 12345 }
+      let(:agency_website) { "bosco.example" } # Columns from the media_information partial
+      let(:facebook) { "facebook" }
+      let(:twitter) { "twitter" }
+      let(:instagram) { "instagram" }
+      let(:no_social_media_presence) { false }
+      let(:enable_quantity_based_requests) { true } # Columns from the partner_settings partial
+      let(:enable_child_based_requests) { true }
+      let(:enable_individual_requests) { true }
+      let(:providing_diapers) { {value: "N", index: -2} }
+      let(:providing_period_supplies) { {value: "N", index: -1} }
+
+      let(:expected_headers) {
         [
-          "Agency Name",
+          "Agency Name", # Technically not part of the agency_information partial, but comes at the start of the export
           "Agency Email",
+          "Notes",
+          "Agency Type", # Columns from the agency_information partial
+          "Other Agency Type",
+          "Agency Mission",
           "Agency Address",
           "Agency City",
           "Agency State",
           "Agency Zip Code",
-          "Agency Website",
-          "Agency Type",
-          "Contact Name",
-          "Contact Phone",
-          "Contact Email",
-          "Notes",
-          "Counties Served",
-          "Providing Diapers",
+          "Program/Delivery Address",
+          "Program City",
+          "Program State",
+          "Program Zip Code",
+          "Agency Website", # Columns from the media_information partial
+          "Facebook",
+          "Twitter",
+          "Instagram",
+          "No Social Media Presence",
+          "Quantity-based Requests", # Columns from the agency_information partial
+          "Child-based Requests",
+          "Individual Requests",
+          "Providing Diapers", # Technically not part of the partner_settings partial, but comes at the end of the export
           "Providing Period Supplies"
-      ]
-      end
+        ]
+      }
+
+      let(:expected_values) {
+        [
+          partner.name, # Technically not part of the agency_information partial, but comes at the start of the export
path: spec/requests/partners_requests_spec.rb
user: login: dorner
body: Can we hardcode these values? Otherwise you basically reproduce the code itself.
created_at: 2025-04-16T16:03:47Z
author_association: COLLABORATOR
diff_hunk: @@ -31,55 +32,112 @@
       let!(:profile) do
         create(:partner_profile,
           partner: partner,
-          primary_contact_name: contact_name,
-          primary_contact_email: contact_email,
-          primary_contact_phone: contact_phone,
+          agency_type: agency_type, # Columns from the agency_information partial
+          other_agency_type: other_agency_type,
+          agency_mission: agency_mission,
           address1: agency_address1,
           address2: agency_address2,
           city: agency_city,
           state: agency_state,
           zip_code: agency_zipcode,
-          website: agency_website,
-          agency_type: agency_type,
-          other_agency_type: other_agency_type)
+          program_address1: program_address1,
+          program_address2: program_address2,
+          program_city: program_city,
+          program_state: program_state,
+          program_zip_code: program_zip_code,
+          website: agency_website, # Columns from the media_information partial
+          facebook: facebook,
+          twitter: twitter,
+          instagram: instagram,
+          no_social_media_presence: no_social_media_presence,
+          enable_child_based_requests: enable_child_based_requests, # Columns from the partner_settings partial
+          enable_individual_requests: enable_individual_requests,
+          enable_quantity_based_requests: enable_quantity_based_requests)
       end
       let(:name) { "Leslie Sue" }
       let(:email) { "leslie@sue.com" }
-      let(:contact_name) { "Jon Ralfeo" }
-      let(:contact_email) { "jon@entertainment720.com" }
-      let(:contact_phone) { "1231231234" }
+      let(:notes) { "Some notes" }
+      let(:agency_type) { :other } # Columns from the agency_information partial
+      let(:other_agency_type) { "Another Agency Name" }
+      let(:agency_mission) { "agency_mission" }
       let(:agency_address1) { "4744 McDermott Mountain" }
       let(:agency_address2) { "333 Never land street" }
       let(:agency_city) { "Lake Shoshana" }
       let(:agency_state) { "ND" }
       let(:agency_zipcode) { "09980-7010" }
-      let(:agency_website) { "bosco.example" }
-      let(:agency_type) { :other }
-      let(:notes) { "Some notes" }
-      let(:other_agency_type) { "Another Agency Name" }
-      let(:providing_diapers) { {value: "N", index: 13} }
-      let(:providing_period_supplies) { {value: "N", index: 14} }
-
-      let(:response_format) { 'csv' }
-      let(:expected_headers) do
+      let(:program_address1) { "program_address1" }
+      let(:program_address2) { "program_address2" }
+      let(:program_city) { "program_city" }
+      let(:program_state) { "program_state" }
+      let(:program_zip_code) { 12345 }
+      let(:agency_website) { "bosco.example" } # Columns from the media_information partial
+      let(:facebook) { "facebook" }
+      let(:twitter) { "twitter" }
+      let(:instagram) { "instagram" }
+      let(:no_social_media_presence) { false }
+      let(:enable_quantity_based_requests) { true } # Columns from the partner_settings partial
+      let(:enable_child_based_requests) { true }
+      let(:enable_individual_requests) { true }
+      let(:providing_diapers) { {value: "N", index: -2} }
+      let(:providing_period_supplies) { {value: "N", index: -1} }
+
+      let(:expected_headers) {
         [
-          "Agency Name",
+          "Agency Name", # Technically not part of the agency_information partial, but comes at the start of the export
           "Agency Email",
+          "Notes",
+          "Agency Type", # Columns from the agency_information partial
+          "Other Agency Type",
+          "Agency Mission",
           "Agency Address",
           "Agency City",
           "Agency State",
           "Agency Zip Code",
-          "Agency Website",
-          "Agency Type",
-          "Contact Name",
-          "Contact Phone",
-          "Contact Email",
-          "Notes",
-          "Counties Served",
-          "Providing Diapers",
+          "Program/Delivery Address",
+          "Program City",
+          "Program State",
+          "Program Zip Code",
+          "Agency Website", # Columns from the media_information partial
+          "Facebook",
+          "Twitter",
+          "Instagram",
+          "No Social Media Presence",
+          "Quantity-based Requests", # Columns from the agency_information partial
+          "Child-based Requests",
+          "Individual Requests",
+          "Providing Diapers", # Technically not part of the partner_settings partial, but comes at the end of the export
           "Providing Period Supplies"
-      ]
-      end
+        ]
+      }
+
+      let(:expected_values) {
+        [
+          partner.name, # Technically not part of the agency_information partial, but comes at the start of the export
path: spec/requests/partners_requests_spec.rb
user: login: dorner
body: Ditto with all subsequent changes.
created_at: 2025-04-16T16:04:02Z
author_association: COLLABORATOR
diff_hunk: @@ -24,23 +28,115 @@ def headers
     end
 
     def base_table
-      {
+      table = {
         "Agency Name" => ->(partner) { partner.name },
         "Agency Email" => ->(partner) { partner.email },
-        "Agency Address" => ->(partner) { partner.agency_info[:address] },
-        "Agency City" => ->(partner) { partner.agency_info[:city] },
-        "Agency State" => ->(partner) { partner.agency_info[:state] },
-        "Agency Zip Code" => ->(partner) { partner.agency_info[:zip_code] },
-        "Agency Website" => ->(partner) { partner.agency_info[:website] },
-        "Agency Type" => ->(partner) { partner.agency_info[:agency_type] },
-        "Contact Name" => ->(partner) { partner.contact_person[:name] },
-        "Contact Phone" => ->(partner) { partner.contact_person[:phone] },
-        "Contact Email" => ->(partner) { partner.contact_person[:email] },
         "Notes" => ->(partner) { partner.notes },
-        "Counties Served" => ->(partner) { county_list_by_regions[partner.id] || "" },
-        "Providing Diapers" => ->(partner) { diaper_statuses[partner.id] },
-        "Providing Period Supplies" => ->(partner) { period_supplies_statuses[partner.id] }
+        "Agency Type" => ->(partner) { I18n.t(partner.profile.agency_type, scope: :partners_profile) }, # Columns from the agency_information partial
+        "Other Agency Type" => ->(partner) { partner.profile.other_agency_type },
+        "Agency Mission" => ->(partner) { partner.profile.agency_mission },
+        "Agency Address" => ->(partner) {
+          (partner.profile.address1.blank? || partner.profile.address2.blank?) ?
+          "" : "#{partner.profile.address1}, #{partner.profile.address2}"
+        },
+        "Agency City" => ->(partner) { partner.profile.city },
+        "Agency State" => ->(partner) { partner.profile.state },
+        "Agency Zip Code" => ->(partner) { partner.profile.zip_code },
+        "Program/Delivery Address" => ->(partner) {
+          (partner.profile.program_address1.blank? || partner.profile.program_address2.blank?) ?
+          "" : "#{partner.profile.program_address1}, #{partner.profile.program_address2}"
+        },
+        "Program City" => ->(partner) { partner.profile.program_city },
+        "Program State" => ->(partner) { partner.profile.program_state },
+        "Program Zip Code" => ->(partner) { partner.profile.program_zip_code }
       }
+
+      if @partials_to_show.include? "media_information"
+        table["Agency Website"] = ->(partner) { partner.profile.website }
+        table["Facebook"] = ->(partner) { partner.profile.facebook }
+        table["Twitter"] = ->(partner) { partner.profile.twitter }
+        table["Instagram"] = ->(partner) { partner.profile.instagram }
+        table["No Social Media Presence"] = ->(partner) { partner.profile.no_social_media_presence }
+      end
+
+      if @partials_to_show.include? "agency_stability"
+        table["Year Founded"] = ->(partner) { partner.profile.founded }
+        table["Form 990 Filed"] = ->(partner) { partner.profile.form_990 }
+        table["Program Name"] = ->(partner) { partner.profile.program_name }
+        table["Program Description"] = ->(partner) { partner.profile.program_description }
+        table["Agency Age"] = ->(partner) { partner.profile.program_age }
+        table["Evidence Based"] = ->(partner) { partner.profile.evidence_based }
+        table["Case Management"] = ->(partner) { partner.profile.case_management }
+        table["How Are Essentials Used"] = ->(partner) { partner.profile.essentials_use }
+        table["Receive Essentials From Other Sources"] = ->(partner) { partner.profile.receives_essentials_from_other }
+        table["Currently Providing Diapers"] = ->(partner) { partner.profile.currently_provide_diapers }
+      end
+
+      if @partials_to_show.include? "organizational_capacity"
+        table["Client Capacity"] = ->(partner) { partner.profile.client_capacity }
+        table["Storage Space"] = ->(partner) { partner.profile.storage_space }
+        table["Storage Space Description"] = ->(partner) { partner.profile.describe_storage_space }
+      end
+
+      if @partials_to_show.include? "sources_of_funding"
+        table["Sources Of Funding"] = ->(partner) { partner.profile.sources_of_funding }
+        table["How do you currently obtain diapers?"] = ->(partner) { partner.profile.sources_of_diapers }
+        table["Essentials Budget"] = ->(partner) { partner.profile.essentials_budget }
+        table["Essentials Funding Source"] = ->(partner) { partner.profile.essentials_funding_source }
+      end
+
+      if @partials_to_show.include? "area_served"
+        table["Area Served"] = ->(partner) { county_list_by_regions[partner.id] || "" }
+      end
+
+      if @partials_to_show.include? "population_served"
+        table["Income Requirement"] = ->(partner) { partner.profile.income_requirement_desc }
+        table["Verify Income"] = ->(partner) { partner.profile.income_verification }
+        table["% African American"] = ->(partner) { partner.profile.population_black }
+        table["% Caucasian"] = ->(partner) { partner.profile.population_white }
+        table["% Hispanic"] = ->(partner) { partner.profile.population_hispanic }
+        table["% Asian"] = ->(partner) { partner.profile.population_asian }
+        table["% American Indian"] = ->(partner) { partner.profile.population_american_indian }
+        table["% Pacific Island"] = ->(partner) { partner.profile.population_island }
+        table["% Multi-racial"] = ->(partner) { partner.profile.population_multi_racial }
+        table["% Other"] = ->(partner) { partner.profile.population_other }
+        table["Zip Codes Served"] = ->(partner) { partner.profile.zips_served }
+        table["% At FPL or Below"] = ->(partner) { partner.profile.at_fpl_or_below }
+        table["% Above 1-2 times FPL"] = ->(partner) { partner.profile.above_1_2_times_fpl }
+        table["% Greater than 2 times FPL"] = ->(partner) { partner.profile.greater_2_times_fpl }
+        table["% Poverty Unknown"] = ->(partner) { partner.profile.poverty_unknown }
+      end
+
+      if @partials_to_show.include? "executive_director"
+        table["Executive Director Name"] = ->(partner) { partner.profile.executive_director_name }
+        table["Executive Director Phone"] = ->(partner) { partner.profile.executive_director_phone }
+        table["Executive Director Email"] = ->(partner) { partner.profile.executive_director_email }
+        table["Primary Contact Name"] = ->(partner) { partner.profile.primary_contact_name }
+        table["Primary Contact Phone"] = ->(partner) { partner.profile.primary_contact_phone }
+        table["Primary Contact Cell"] = ->(partner) { partner.profile.primary_contact_mobile }
+        table["Primary Contact Email"] = ->(partner) { partner.profile.primary_contact_email }
+      end
+
+      if @partials_to_show.include? "pick_up_person"
+        table["Pick Up Person Name"] = ->(partner) { partner.profile.pick_up_name }
+        table["Pick Up Person Phone"] = ->(partner) { partner.profile.pick_up_phone }
+        table["Pick Up Person Email"] = ->(partner) { partner.profile.pick_up_email }
+      end
+
+      if @partials_to_show.include? "agency_distribution_information"
+        table["Distribution Times"] = ->(partner) { partner.profile.distribution_times }
+        table["New Client Times"] = ->(partner) { partner.profile.new_client_times }
+        table["More Docs Required"] = ->(partner) { partner.profile.more_docs_required }
+      end
+
+      table["Quantity-based Requests"] = ->(partner) { partner.profile.enable_quantity_based_requests } # Columns from the partner_settings partial
+      table["Child-based Requests"] = ->(partner) { partner.profile.enable_child_based_requests }
+      table["Individual Requests"] = ->(partner) { partner.profile.enable_individual_requests }
+
+      table["Providing Diapers"] = ->(partner) { diaper_statuses[partner.id] }
+      table["Providing Period Supplies"] = ->(partner) { period_supplies_statuses[partner.id] }
+
+      table
path: app/services/exports/export_partners_csv_service.rb
user: login: Benjamin-Couey
body: I split up the function in this recent [commit](https://github.com/rubyforgood/human-essentials/pull/5142/commits/bc5735d38d52fe398c952c6f8e04de4851e7b79a).
created_at: 2025-04-17T15:45:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,55 +32,112 @@
       let!(:profile) do
         create(:partner_profile,
           partner: partner,
-          primary_contact_name: contact_name,
-          primary_contact_email: contact_email,
-          primary_contact_phone: contact_phone,
+          agency_type: agency_type, # Columns from the agency_information partial
+          other_agency_type: other_agency_type,
+          agency_mission: agency_mission,
           address1: agency_address1,
           address2: agency_address2,
           city: agency_city,
           state: agency_state,
           zip_code: agency_zipcode,
-          website: agency_website,
-          agency_type: agency_type,
-          other_agency_type: other_agency_type)
+          program_address1: program_address1,
+          program_address2: program_address2,
+          program_city: program_city,
+          program_state: program_state,
+          program_zip_code: program_zip_code,
+          website: agency_website, # Columns from the media_information partial
+          facebook: facebook,
+          twitter: twitter,
+          instagram: instagram,
+          no_social_media_presence: no_social_media_presence,
+          enable_child_based_requests: enable_child_based_requests, # Columns from the partner_settings partial
+          enable_individual_requests: enable_individual_requests,
+          enable_quantity_based_requests: enable_quantity_based_requests)
       end
       let(:name) { "Leslie Sue" }
       let(:email) { "leslie@sue.com" }
-      let(:contact_name) { "Jon Ralfeo" }
-      let(:contact_email) { "jon@entertainment720.com" }
-      let(:contact_phone) { "1231231234" }
+      let(:notes) { "Some notes" }
+      let(:agency_type) { :other } # Columns from the agency_information partial
+      let(:other_agency_type) { "Another Agency Name" }
+      let(:agency_mission) { "agency_mission" }
       let(:agency_address1) { "4744 McDermott Mountain" }
       let(:agency_address2) { "333 Never land street" }
       let(:agency_city) { "Lake Shoshana" }
       let(:agency_state) { "ND" }
       let(:agency_zipcode) { "09980-7010" }
-      let(:agency_website) { "bosco.example" }
-      let(:agency_type) { :other }
-      let(:notes) { "Some notes" }
-      let(:other_agency_type) { "Another Agency Name" }
-      let(:providing_diapers) { {value: "N", index: 13} }
-      let(:providing_period_supplies) { {value: "N", index: 14} }
-
-      let(:response_format) { 'csv' }
-      let(:expected_headers) do
+      let(:program_address1) { "program_address1" }
+      let(:program_address2) { "program_address2" }
+      let(:program_city) { "program_city" }
+      let(:program_state) { "program_state" }
+      let(:program_zip_code) { 12345 }
+      let(:agency_website) { "bosco.example" } # Columns from the media_information partial
+      let(:facebook) { "facebook" }
+      let(:twitter) { "twitter" }
+      let(:instagram) { "instagram" }
+      let(:no_social_media_presence) { false }
+      let(:enable_quantity_based_requests) { true } # Columns from the partner_settings partial
+      let(:enable_child_based_requests) { true }
+      let(:enable_individual_requests) { true }
+      let(:providing_diapers) { {value: "N", index: -2} }
+      let(:providing_period_supplies) { {value: "N", index: -1} }
+
+      let(:expected_headers) {
         [
-          "Agency Name",
+          "Agency Name", # Technically not part of the agency_information partial, but comes at the start of the export
           "Agency Email",
+          "Notes",
+          "Agency Type", # Columns from the agency_information partial
+          "Other Agency Type",
+          "Agency Mission",
           "Agency Address",
           "Agency City",
           "Agency State",
           "Agency Zip Code",
-          "Agency Website",
-          "Agency Type",
-          "Contact Name",
-          "Contact Phone",
-          "Contact Email",
-          "Notes",
-          "Counties Served",
-          "Providing Diapers",
+          "Program/Delivery Address",
+          "Program City",
+          "Program State",
+          "Program Zip Code",
+          "Agency Website", # Columns from the media_information partial
+          "Facebook",
+          "Twitter",
+          "Instagram",
+          "No Social Media Presence",
+          "Quantity-based Requests", # Columns from the agency_information partial
+          "Child-based Requests",
+          "Individual Requests",
+          "Providing Diapers", # Technically not part of the partner_settings partial, but comes at the end of the export
           "Providing Period Supplies"
-      ]
-      end
+        ]
+      }
+
+      let(:expected_values) {
+        [
+          partner.name, # Technically not part of the agency_information partial, but comes at the start of the export
path: spec/requests/partners_requests_spec.rb
user: login: Benjamin-Couey
body: I modified the specs to expect hard-coded values in this recent [commit](https://github.com/rubyforgood/human-essentials/pull/5142/commits/5433806a6d8836f7c9ed11bd15ec4c2bdb379954).
created_at: 2025-04-17T15:46:56Z
author_association: CONTRIBUTOR

PR comments:
user: login: cielf
created_at: 2025-04-04T00:11:08Z
body: "Currently, the ExportPartnersCSVService can only handle being passed a list of partners from more than one organization. Modifying it to handle that case seemed outside the scope of this PR." 

(Looks puzzled.)   Really?   That seems wrong -- you'd never export partners from more than one organization.    Hoping it's a mis-speak.

(Edit:  For clarity When I say organization, I mean bank -- the model for bank is organization)


author_association: COLLABORATOR
user: login: Benjamin-Couey
created_at: 2025-04-04T15:18:04Z
body: > Hey @Benjamin-Couey -- I've taken a light stab at the functional testing and I've noticed one thing I'd like to change. It looks to me like you've put all the mandatory fields first, then the user-configured fields.
> 
> Would it be reasonable to get the fields in the same order as they are in the profile as seen by the banks? (for example, the Child-based requests, etc would be at the end)

That should be doable.

For fields that are part of the mandatory fields but belong to an optional partial (for example `primary_contact_name` from the `executive_director` partial or `website` from the `media_information` partial), I'm thinking of making them optional and sorted with the other fields from their partial since were already changing the order. Does that sound good?
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-04-04T15:52:34Z
body: I'm *pretty* sure that those fields are only mandatory if the partial is included.   Please do keep them with their partials.

My ideal at this point is that all the fields are in the same order as they are displayed.  Of course we have the partner fields first, and then the partner profile fields.    IIRC there are two calculated fields about whether the partner gets/distributes certain types of things.  Those can stay where they are, I think.  
author_association: COLLABORATOR
user: login: Benjamin-Couey
created_at: 2025-04-05T22:27:42Z
body: > "Currently, the ExportPartnersCSVService can only handle being passed a list of partners from more than one organization. Modifying it to handle that case seemed outside the scope of this PR."
> 
> (Looks puzzled.) Really? That seems wrong -- you'd never export partners from more than one organization. Hoping it's a mis-speak.
> 
> (Edit: For clarity When I say organization, I mean bank -- the model for bank is organization)

Sorry for missing this comment, but you are correct. The service can only export partners from a single organization. I made a typo on the PR.
author_association: CONTRIBUTOR
user: login: Benjamin-Couey
created_at: 2025-04-07T19:30:26Z
body: > Hey @Benjamin-Couey -- I've taken a light stab at the functional testing and I've noticed one thing I'd like to change. It looks to me like you've put all the mandatory fields first, then the user-configured fields.
> 
> Would it be reasonable to get the fields in the same order as they are in the profile as seen by the banks? (for example, the Child-based requests, etc would be at the end)

@cielf Most recent commit should rework the export to have the fields in the same order as they appear in the partner profile form.
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-04-09T19:33:20Z
body: Thanks -- it might take me a few days to get this tested.  We'll see.
author_association: COLLABORATOR
user: login: cielf
created_at: 2025-04-11T18:14:23Z
body: Hey @Benjamin-Couey This is technically out of scope, but if #5075   progresses reasonably well, i'd  like to get that field in at the same time, so we don't have two changes to the export happening one on top of the other..   (It would go right after notes)
author_association: COLLABORATOR
user: login: Benjamin-Couey
created_at: 2025-04-13T13:49:24Z
body: > Hey @Benjamin-Couey This is technically out of scope, but if #5075 progresses reasonably well, i'd like to get that field in at the same time, so we don't have two changes to the export happening one on top of the other.. (It would go right after notes)

Can do. I'll keep an eye on #5075.

> Hey @Benjamin-Couey
> 
> It looks like we still have some crossed wires. We're definitely going to need to do some communication to the banks when this goes out!
> 
> See attached --- I think it's self-explanatory, but if something's unclear, or you think I'm just wrong, please don't hesitate to reach out.
> 
> [Partner export notes.pdf](https://github.com/user-attachments/files/19712047/Partner.export.notes.pdf)

Apologies for the issues, and thank you for the clear notes you provided. Looking at the notes, they all make sense and I will start implementing them.

Regarding the communication to the banks, is that something you'd like me to contribute to?
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-04-13T23:43:34Z
body: I think I can handle it.  It's mostly just a note that we need to put it front and center in the announcements and newsletter for the week.  Thanks!
author_association: COLLABORATOR
user: login: Benjamin-Couey
created_at: 2025-04-14T17:53:19Z
body: @cielf The most recent commits should rework the export to have the correct order of fields as outlined in the notes you put together.
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-04-16T13:54:55Z
body: LGTM functionally.  Over to @dorner for technical review.    @dorner -- please note above comments about #5075.
author_association: COLLABORATOR
user: login: Benjamin-Couey
created_at: 2025-04-17T15:49:11Z
body: @dorner the changes you requested should be addressed by the most recent commits.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T14:25:57Z
body: @Benjamin-Couey: Your PR `4946 partner profile export` is part of today's Human Essentials production release: [2025.04.27](https://github.com/rubyforgood/human-essentials/releases/tag/2025.04.27). 
Thank you very much for your contribution!
author_association: CONTRIBUTOR