Skip to content

Conversation

@erawat
Copy link
Member

@erawat erawat commented Dec 9, 2025

Overview

Add native support for handling contribution overpayments. When a contact pays more than the invoice amount, the contribution enters "Pending refund" status. This PR allows users to allocate that overpayment to a new credit note, which can then be applied to future
invoices.

Before

When a contribution is overpaid:

  • Contribution status shows "Pending refund"
  • No way to convert the overpayment into usable credit
  • Manual workarounds required to handle overpayments

After

  • New "Enable Overpayments" setting in CiviContribute settings
  • New "Overpayment Financial Type" field on Company entity
  • New "Allocate overpayment to new credit note" action on contributions with "Pending refund" status
  • Clicking the action opens a confirmation dialog showing the contact and amount
  • After allocation:
    • Credit note is created with "Open" status and full credit available
    • Contribution status changes from "Pending refund" to "Completed"
    • Credit can be applied to future invoices
Screenshot 2025-12-09 at 12 44 14 Screenshot 2025-12-09 at 12 44 27 Screenshot 2025-12-09 at 12 44 32

Technical Details

New API Action: CreditNote::allocateOverpayment()
CreditNote::allocateOverpayment(FALSE)
->setContributionId($contributionId)
->execute();

Key Implementation Notes:

  • Credit note is created with "Open" status (no allocation to the contribution itself)
  • A negative payment is recorded on the contribution using CRM_Financial_BAO_Payment::create()
  • CiviCRM's Payment API hardcodes "Refunded" status for negative amounts, so we update the transaction to "Completed" status after creation
  • Eligibility requires: setting enabled, contribution in "Pending refund" status, and overpayment financial type configured on the company

Database: New column overpayment_financial_type_id added to civicrm_financeextras_company table

Multi-Company Support

The overpayment allocation uses the company's configured Accounts Receivable Payment Method to determine the financial accounts for the transaction. This ensures correct accounting in multi-company setups.

How it works:

  • Gets the receivable_payment_method from the company associated with the contribution's owner organization
  • Uses that payment method as the payment instrument for the adjustment transaction
  • Gets the Accounts Receivable financial account from the company's configured payment method using getInstrumentFinancialAccount()
  • Both sides of the transaction (from/to) use this Accounts Receivable account since this is an internal allocation, not actual money movement

Why this matters:

  • Different companies can have different Accounts Receivable accounts configured
  • The overpayment adjustment will use the correct AR account for that company
  • Ensures proper financial reporting per company

@erawat erawat force-pushed the FOSFASPRT-78-overpayments branch 2 times, most recently from 41a95fa to 02266aa Compare December 9, 2025 10:31
@erawat
Copy link
Member Author

erawat commented Dec 9, 2025

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@erawat erawat force-pushed the FOSFASPRT-78-overpayments branch from 02266aa to 05d9420 Compare December 9, 2025 10:41
Add ability to allocate overpayments from contributions to credit notes.

Features:
- New CreditNote.allocateOverpayment API action
- Company setting for overpayment financial type
- Admin setting to enable/disable overpayments feature
- "Allocate overpayment" link on overpaid contributions
- Creates credit note with overpayment amount as line item
- Records negative payment on contribution to balance it

Database changes:
- Added overpayment_financial_type_id column to Company table
- New upgrade_1006.sql migration
@erawat erawat force-pushed the FOSFASPRT-78-overpayments branch from 05d9420 to 8f5699b Compare December 9, 2025 10:48
@erawat
Copy link
Member Author

erawat commented Dec 9, 2025

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@erawat erawat marked this pull request as ready for review December 9, 2025 13:06
@shahrukh-compuco
Copy link
Contributor

@codex review

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds native support for handling contribution overpayments by allowing users to allocate overpayments to new credit notes. When a contribution is overpaid (in "Pending refund" status), users can now convert the excess payment into a credit note for future invoice allocation.

Key Changes:

  • New "Enable Overpayments" setting in CiviContribute configuration
  • New "Overpayment Financial Type" field on Company entity for configuring which financial type to use
  • New CreditNote::allocateOverpayment() API action to convert overpayments to credit notes

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
xml/schema/CRM/Financeextras/Company.xml Adds overpayment_financial_type_id field to Company schema
xml/Menu/financeextras.xml Registers new overpayment allocation form route
tests/phpunit/Civi/Api4/Action/CreditNote/AllocateOverpaymentActionTest.php Comprehensive test coverage for overpayment allocation
templates/CRM/Financeextras/Page/Company.tpl Adds overpayment financial type column to company listing
templates/CRM/Financeextras/OverpaymentFinancialType.hlp Help text for configuring overpayment financial types
templates/CRM/Financeextras/Form/Contribute/OverpaymentAllocate.tpl Confirmation dialog template for allocating overpayments
templates/CRM/Financeextras/Form/Company/Add.tpl Adds overpayment financial type field to company form
sql/upgrade_1006.sql Migration to add overpayment_financial_type_id column
sql/auto_install.sql Updates auto-install schema with new field and constraint
settings/financeextras.setting.php Defines the enable overpayments setting
Civi/Financeextras/Utils/OverpaymentUtils.php Utility functions for overpayment detection and eligibility
Civi/Financeextras/Hook/Links/Contribution/Overpayment.php Adds overpayment allocation link to contribution actions
Civi/Financeextras/Hook/Links/Contribution.php Integrates overpayment link handler
Civi/Api4/CreditNote.php Registers allocateOverpayment API action
Civi/Api4/Action/CreditNote/AllocateOverpaymentAction.php Core implementation of overpayment allocation logic
CRM/Financeextras/Upgrader.php Adds upgrade_1006 method for database migration
CRM/Financeextras/Page/Company.php Updates company listing query to include overpayment financial type
CRM/Financeextras/Form/Contribute/OverpaymentAllocate.php Form controller for overpayment allocation
CRM/Financeextras/Form/Company/Add.php Adds overpayment financial type field handling
CRM/Financeextras/DAO/Company.php Generated DAO updates for new overpayment_financial_type_id field

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to +20
$getQuery = 'SELECT fc.*, cc.display_name as company_name, mt.msg_title as invoice_template_name, mt2.msg_title as creditnote_template_name, ov.label AS receivable_payment_method, ft.name AS overpayment_financial_type_name FROM financeextras_company fc
LEFT JOIN civicrm_contact cc on cc.id = fc.contact_id
LEFT JOIN civicrm_msg_template mt ON mt.id = fc.invoice_template_id
LEFT JOIN civicrm_msg_template mt2 ON mt2.id = fc.creditnote_template_id
LEFT JOIN civicrm_option_value ov ON ov.value = fc.receivable_payment_method AND ov.option_group_id = ' . $optionGroupId . ' ORDER BY fc.id DESC
LEFT JOIN civicrm_option_value ov ON ov.value = fc.receivable_payment_method AND ov.option_group_id = ' . $optionGroupId . '
LEFT JOIN civicrm_financial_type ft ON ft.id = fc.overpayment_financial_type_id
ORDER BY fc.id DESC
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

[nitpick] SQL query is difficult to read and maintain as a single concatenated string. Consider using a multi-line heredoc or nowdoc syntax for better readability and maintainability.

Copilot uses AI. Check for mistakes.
@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- Look up tax rate from Sales Tax Account linked to the overpayment
  financial type instead of hardcoding tax_amount to 0
- Pass tax_rate to CreditNote::save() which calculates tax_amount
  using the same code path as UI-created credit notes
- Add test for tax calculation when financial type has tax configured
- Change payment instrument from 'credit_note' to 'accounts_receivable'
  since this is an internal allocation, not actual money movement
- Set both from/to financial accounts to Accounts Receivable from the
  contribution's financial type (instead of using bank account)
- Get receivable_payment_method from company instead of using
  hardcoded accounts_receivable payment instrument
- Get AR financial account from company's configured payment method
  using getInstrumentFinancialAccount() for multi-company support
@erawat
Copy link
Member Author

erawat commented Dec 10, 2025

@codex review

1 similar comment
@erawat
Copy link
Member Author

erawat commented Dec 10, 2025

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 185 to 189
'description' => ts('Overpayment %1', [1 => $todayFormatted]),
'financial_type_id' => $financialTypeId,
'quantity' => 1,
'unit_price' => $amount,
'tax_rate' => $taxRate,

Choose a reason for hiding this comment

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

P1 Badge Avoid adding tax on top of overpayment amount

When the overpayment financial type has a sales tax account, the credit note line is created with unit_price equal to the full overpayment and a non‑zero tax_rate. Because the overpayment amount is already the gross cash paid (computed as total payments minus the contribution’s tax‑inclusive total), CreditNote::save will add tax on top and produce a credit note larger than the overpayment (e.g. a £50 overpayment with 20% tax becomes a £60 credit), leaving accounting out of balance. Treat the overpayment as tax‑inclusive or derive a net unit price before applying tax so total credit does not exceed the overpayment.

Useful? React with 👍 / 👎.

@erawat
Copy link
Member Author

erawat commented Dec 10, 2025

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

The overpayment amount is already gross cash (total_payments minus
contribution_total), where contribution_total is tax-inclusive.
Adding tax would inflate the credit note beyond the actual overpayment.
@erawat erawat force-pushed the FOSFASPRT-78-overpayments branch from 0ae62a4 to d472b55 Compare December 10, 2025 12:20
@erawat erawat merged commit c76535c into master Dec 11, 2025
2 checks passed
@erawat erawat deleted the FOSFASPRT-78-overpayments branch December 11, 2025 08:11
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.

3 participants