Skip to content

CIVIMM-462: Add instalment generation scheduled job for recurring contributions#12

Merged
erawat merged 3 commits intomasterfrom
CIVIMM-462-instalment-generation-job
Feb 2, 2026
Merged

CIVIMM-462: Add instalment generation scheduled job for recurring contributions#12
erawat merged 3 commits intomasterfrom
CIVIMM-462-instalment-generation-job

Conversation

@erawat
Copy link
Member

@erawat erawat commented Jan 27, 2026

Overview

Adds a scheduled job that creates Pending contribution records for each due In Progress recurring contribution not linked to a membership. No payment processor calls are made.

Also introduces a typed RecurringContributionDTO, fixes PHPStan stub resolution, and adds AI playbook configuration for multi-agent development.

Before

  • No mechanism to automatically generate instalment contributions for due recurring contributions
  • Monolithic CLAUDE.md with no shared standards for other AI tools

After

Instalment generation

A new scheduled job (InstalmentGenerator.Run) queries due In Progress recurring contributions, excludes membership-linked ones, checks idempotency, creates a Pending contribution, and advances next_sched_contribution_date with correct end-of-month handling.

Typed DTO boundary

RecurringContributionDTO::fromApiResult() converts CiviCRM's untyped Api4 arrays into a typed object at the service boundary, eliminating manual validation and "Cannot cast mixed" PHPStan errors.

AI playbook

Restructured CLAUDE.md into a thin wrapper referencing shared standards in .ai/. Added configs for Gemini, Codex, and Copilot so all AI tools follow the same conventions.

Technical Details

DTO pattern: RecurringContributionDTO validates required fields (id, contact_id, next_sched_contribution_date), applies defaults (frequency_unit'month', frequency_interval1), and guarantees types via a private constructor with a static factory method.

Contribution.create over repeattransaction: repeattransaction copies from a template contribution and triggers side effects (receipts, hooks, tax). We need a clean Pending record with fields from the recurring contribution directly.

Atomicity: Each instalment creation + schedule advance is wrapped in CRM_Core_Transaction. If either fails, both roll back.

End-of-month handling: Monthly advancement uses first day of +N month then clamps to the target month's last day, avoiding PHP DateTime overflow (Jan 31 + 1 month → Mar 3).

AI playbook architecture: Tool-specific thin wrappers (CLAUDE.md, AGENTS.md, GEMINI.md) reference shared standards in .ai/. .claude/settings.json and slash commands (/pre-commit, /review) are tracked in the repo. settings.local.json is gitignored for per-developer overrides.

Core overrides

None.

Comments

  • Job defaults: processor_type=Stripe, batch_size=500 (both configurable)
  • Zero new PHPStan baseline entries from this PR

@gemini-code-assist
Copy link

Summary of Changes

Hello @erawat, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant automation feature to CiviCRM by implementing a scheduled job that generates instalment contributions for recurring donations. This job streamlines the process of creating "invoice" records for non-membership recurring contributions that are due, ensuring timely record creation without manual intervention or reliance on processor-specific logic. It focuses solely on record generation, explicitly avoiding any payment processor communication, and includes robust checks for idempotency and membership exclusion.

Highlights

  • Automated Instalment Generation: Introduced a new scheduled job (InstalmentGenerator.Run) to automatically create 'Pending' contribution records for due 'In Progress' recurring contributions.
  • Membership Exclusion: Recurring contributions linked to memberships are explicitly excluded from this automated generation process.
  • Idempotency Ensured: The system checks for existing 'Pending', 'Completed', 'Failed', or 'Cancelled' contributions for the same recurring contribution and date to prevent duplicate instalment creation.
  • API3 Integration: Utilizes the Contribution.repeattransaction API3 for creating new instalments, ensuring that line items, custom fields, and soft credits are copied from the template contribution.
  • Configurable Parameters: The scheduled job and its underlying API endpoint (InstalmentGenerator.Run) allow configuration of processor_type (defaulting to "Stripe") and batch_size.
  • UI Enhancement: The 'Memberships' tab is now hidden on contribution page administration settings, as the platform does not support membership integration on these pages.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@erawat erawat changed the title CIVIMM-462: Add instalment generation scheduled job for recurring contributions [WIP] CIVIMM-462: Add instalment generation scheduled job for recurring contributions Jan 27, 2026
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a scheduled job to generate instalments for recurring contributions, which is a valuable addition. The implementation is well-structured, featuring a dedicated service, an API endpoint, and a managed job definition. The inclusion of comprehensive unit tests is particularly commendable.

I have identified two high-severity issues. The first is a logic bug in how due contributions are queried, which could lead to instalments being processed a day late. The second concerns overly defensive code that can mask data problems and lead to incorrect behavior when checking for existing instalments. I've provided specific suggestions to address these points. With these changes, this will be a very solid feature.

@erawat erawat force-pushed the CIVIMM-462-instalment-generation-job branch 8 times, most recently from e4000ea to 4fdc210 Compare January 28, 2026 09:09
@erawat erawat force-pushed the CIVIMM-462-instalment-generation-job branch from 4fdc210 to d37b3a1 Compare February 2, 2026 10:06
@erawat erawat changed the title [WIP] CIVIMM-462: Add instalment generation scheduled job for recurring contributions CIVIMM-462: Add instalment generation scheduled job for recurring contributions Feb 2, 2026
@erawat
Copy link
Member Author

erawat commented Feb 2, 2026

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is an excellent pull request that introduces a valuable new feature for generating instalments for recurring contributions. The implementation in InstalmentGenerationService is robust, with great attention to details like transaction atomicity, idempotency, and edge-case handling for date calculations. The new API endpoint and scheduled job are well-defined.

I'm particularly impressed by the comprehensive test suite, which covers a wide range of scenarios and ensures the reliability of the new service. The work to improve the PHPStan configuration with stubs for Api4 entities is also a significant contribution to the project's long-term code quality and maintainability.

I have one minor suggestion for improving code clarity, but overall this is a high-quality contribution.

@erawat erawat force-pushed the CIVIMM-462-instalment-generation-job branch 7 times, most recently from 017eb9b to 00c0582 Compare February 2, 2026 12:14
@erawat erawat force-pushed the CIVIMM-462-instalment-generation-job branch from 00c0582 to aef0cf8 Compare February 2, 2026 12:20
@erawat erawat force-pushed the CIVIMM-462-instalment-generation-job branch from f92339b to 48736b0 Compare February 2, 2026 13:15
@erawat erawat merged commit 8a1a6d3 into master Feb 2, 2026
3 checks passed
@erawat erawat deleted the CIVIMM-462-instalment-generation-job branch February 2, 2026 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants