What's needed
Same pattern as the other CRM bridges in philanthropy.ingest (CiviCRM, Raiser's Edge, NPSP): a thin, CRM-specific header-alias map plus a commitment/payment exclusion filter, delegating the roll-up to the shared aggregator in philanthropy/ingest/_civicrm.py. This issue adds the bridge for Ellucian CRM Advance (higher-education advancement CRM, formerly "Advance"/"Advance Web") — a different vendor from every bridge in this repo so far, with its own object model (a gift is typically a "Designation"-linked transaction against a constituent record). Confirm the actual field names and vocabulary from Ellucian's own docs; nothing here should be assumed from the existing bridges.
Where to look
| File |
Purpose |
philanthropy/ingest/_raisers_edge.py |
Closest existing example of the pattern (structure only — a different vendor and data model, not a source of field names) |
philanthropy/ingest/_civicrm.py |
The shared aggregator (civicrm_contributions_to_features, read_civicrm_contributions) and its private helpers |
tests/test_raisers_edge.py |
The test depth expected of your new tests/test_ellucian_advance.py |
philanthropy/cli.py |
_FEATURE_SOURCES and the features --source dispatch — wire your new source in the same shape, unless the read_gifts preset registry (a separate, in-flight PR) has already landed, in which case register there instead |
What to build
philanthropy/ingest/_ellucian_advance.py: a header-alias map from Ellucian CRM Advance's real export labels and API field names onto the canonical contact_id / receive_date / total_amount / gift_type names; a documented default exclusion parameter for whatever this product's pledge-vs-payment split actually is; a ellucian_advance_gifts_to_features(...) function (name it for what the product actually calls the record once you've checked); and a read_ellucian_advance_gifts(path) reader delegating to read_civicrm_contributions.
- Verify every field name and every commitment/payment vocabulary term against Ellucian's own public documentation before writing it down. Cite the doc URLs you actually used in your PR body, the way PR #233 does for NPSP. This issue does not assert any field name as fact — confirm everything yourself.
- Export the new names from
philanthropy/ingest/__init__.py (__all__, alphabetical) and add a stability-tier row to docs/reference/index.md (Tier 2/Beta — a test enforces every public symbol has a row).
tests/test_ellucian_advance.py at the depth of tests/test_raisers_edge.py: header aliasing from every spelling the docs name, the commitment/payment double-count trap and its exclusion, the exclusion set being documented/overridable/disabled by None, currency parsing, schema/dtypes, empty input, missing required columns.
CHANGELOG.md entry under ## [Unreleased], and add yourself to CONTRIBUTORS.md if you'd like.
Hard constraints (same as the rest of this ingest series)
- Dependencies stay scikit-learn/pandas/numpy/joblib only — no new package, no API client, no network code anywhere in
philanthropy/. File-export reader only, never a live API connector.
- No new estimator class.
- Build the exclusion logic from Ellucian's own public docs only — never from an institution's actual configuration or data.
- Follow AGENTS.md's order: implement, export, verify with
python -c "...", then write tests, then make ci.
Verifying
python -m pip install -e ".[dev]"
python -c "from philanthropy.ingest import ellucian_advance_gifts_to_features, read_ellucian_advance_gifts; print('OK')"
make ci
make riskcov
Claim this issue with a comment before starting; a maintainer assigns within 24 hours.
What's needed
Same pattern as the other CRM bridges in
philanthropy.ingest(CiviCRM, Raiser's Edge, NPSP): a thin, CRM-specific header-alias map plus a commitment/payment exclusion filter, delegating the roll-up to the shared aggregator inphilanthropy/ingest/_civicrm.py. This issue adds the bridge for Ellucian CRM Advance (higher-education advancement CRM, formerly "Advance"/"Advance Web") — a different vendor from every bridge in this repo so far, with its own object model (a gift is typically a "Designation"-linked transaction against a constituent record). Confirm the actual field names and vocabulary from Ellucian's own docs; nothing here should be assumed from the existing bridges.Where to look
philanthropy/ingest/_raisers_edge.pyphilanthropy/ingest/_civicrm.pycivicrm_contributions_to_features,read_civicrm_contributions) and its private helperstests/test_raisers_edge.pytests/test_ellucian_advance.pyphilanthropy/cli.py_FEATURE_SOURCESand thefeatures --sourcedispatch — wire your new source in the same shape, unless theread_giftspreset registry (a separate, in-flight PR) has already landed, in which case register there insteadWhat to build
philanthropy/ingest/_ellucian_advance.py: a header-alias map from Ellucian CRM Advance's real export labels and API field names onto the canonicalcontact_id/receive_date/total_amount/gift_typenames; a documented default exclusion parameter for whatever this product's pledge-vs-payment split actually is; aellucian_advance_gifts_to_features(...)function (name it for what the product actually calls the record once you've checked); and aread_ellucian_advance_gifts(path)reader delegating toread_civicrm_contributions.philanthropy/ingest/__init__.py(__all__, alphabetical) and add a stability-tier row todocs/reference/index.md(Tier 2/Beta — a test enforces every public symbol has a row).tests/test_ellucian_advance.pyat the depth oftests/test_raisers_edge.py: header aliasing from every spelling the docs name, the commitment/payment double-count trap and its exclusion, the exclusion set being documented/overridable/disabled byNone, currency parsing, schema/dtypes, empty input, missing required columns.CHANGELOG.mdentry under## [Unreleased], and add yourself toCONTRIBUTORS.mdif you'd like.Hard constraints (same as the rest of this ingest series)
philanthropy/. File-export reader only, never a live API connector.python -c "...", then write tests, thenmake ci.Verifying
Claim this issue with a comment before starting; a maintainer assigns within 24 hours.