Conversation
WalkthroughThe changes introduce a new method, Changes
Possibly related PRs
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (2)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (2)
1451-1451: Remove debug logging statement.The
error_logstatement should be removed as it appears to be temporary debugging code.- error_log("contributionId: " . print_r($contributionId, TRUE));
1456-1456: Fix incorrect error message.The error message references the wrong method name.
- \Civi::log()->error("Exception occurred in updateCampaignForCollectionSourceContribution.", [ + \Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [
| public static function generateInvoiceIdForContribution(string $op, string $objectName, int $objectId, &$objectRef) { | ||
| if ($objectName !== 'Contribution' || !$objectRef->id || $op !== 'edit') { | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| $contributionId = $objectRef->id; | ||
| if (!$contributionId) { | ||
| return; | ||
| } | ||
|
|
||
| error_log("contributionId: " . print_r($contributionId, TRUE)); | ||
|
|
||
| } | ||
|
|
||
| catch (\Exception $e) { | ||
| \Civi::log()->error("Exception occurred in updateCampaignForCollectionSourceContribution.", [ | ||
| 'Message' => $e->getMessage(), | ||
| 'Stack Trace' => $e->getTraceAsString(), | ||
| ]); | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
Implement invoice generation logic.
The method is currently incomplete. It only checks for conditions and logs the contributionId without implementing the actual invoice generation logic. Based on the PR title "Generate Invoice Id", this is the core functionality that needs to be implemented.
Consider:
- Generating a unique invoice ID
- Updating the contribution record with the generated invoice ID
- Adding appropriate validation and error handling
- Adding logging for successful invoice generation
Would you like me to help design and implement the invoice generation logic?
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php(2 hunks)
🔇 Additional comments (1)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (1)
56-56: LGTM: Event handler registration is correct.
The new event handler is properly registered for the post-write hook.
| /** | ||
| * This hook is called after a db write on entities. | ||
| * | ||
| * @param string $op | ||
| * The type of operation being performed. | ||
| * @param string $objectName | ||
| * The name of the object. | ||
| * @param int $objectId | ||
| * The unique identifier for the object. | ||
| * @param object $objectRef | ||
| * The reference to the object. | ||
| */ | ||
| public static function generateInvoiceIdForContribution(string $op, string $objectName, int $objectId, &$objectRef) { | ||
| if ($objectName !== 'Contribution' || !$objectRef->id) { | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| $contributionId = $objectRef->id; | ||
| if (!$contributionId) { | ||
| return; | ||
| } | ||
|
|
||
| error_log("contributionId: " . print_r($contributionId, TRUE)); | ||
|
|
||
| if (!empty($objectRef->invoice_id)) { | ||
| return; | ||
| } | ||
|
|
||
| $results = Contribution::update(TRUE) | ||
| ->addValue('invoice_id', 'tarun') | ||
| ->addWhere('id', '=', $contributionId) | ||
| ->execute(); | ||
|
|
||
| } | ||
|
|
||
| catch (\Exception $e) { | ||
| \Civi::log()->error("Exception occurred in updateCampaignForCollectionSourceContribution.", [ | ||
| 'Message' => $e->getMessage(), | ||
| 'Stack Trace' => $e->getTraceAsString(), | ||
| ]); | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
💡 Codebase verification
Critical: Invoice ID implementation deviates from CiviCRM core patterns and best practices
The current implementation has several issues when compared to CiviCRM core's invoice ID handling:
- Hardcoding 'tarun' as invoice_id violates CiviCRM's established pattern where invoice IDs are generated using
md5(uniqid(rand(), TRUE))as seen in Contribution/Transact.php - Debug logging via error_log should be removed as CiviCRM provides proper logging via
\Civi::log() - The error message references wrong method name "updateCampaignForCollectionSourceContribution" instead of "generateInvoiceIdForContribution"
public static function generateInvoiceIdForContribution(string $op, string $objectName, int $objectId, &$objectRef) {
if ($objectName !== 'Contribution' || !$objectRef->id) {
return;
}
try {
$contributionId = $objectRef->id;
if (!$contributionId) {
return;
}
- error_log("contributionId: " . print_r($contributionId, TRUE));
-
if (!empty($objectRef->invoice_id)) {
return;
}
$results = Contribution::update(TRUE)
- ->addValue('invoice_id', 'tarun')
+ ->addValue('invoice_id', md5(uniqid(rand(), TRUE)))
->addWhere('id', '=', $contributionId)
->execute();
}
catch (\Exception $e) {
- \Civi::log()->error("Exception occurred in updateCampaignForCollectionSourceContribution.", [
+ \Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [
'Message' => $e->getMessage(),
'Stack Trace' => $e->getTraceAsString(),
]);
}
}🔗 Analysis chain
Critical: Invoice ID generation implementation needs significant improvements.
The current implementation has several issues that need to be addressed:
- The invoice ID is hardcoded as 'tarun' instead of generating a proper unique identifier
- Using
error_logfor debugging (line 1451) should be removed in production code - The error message in the catch block refers to the wrong method name
- Missing proper invoice ID format/pattern
- No validation for duplicate invoice IDs
Consider implementing the following improvements:
public static function generateInvoiceIdForContribution(string $op, string $objectName, int $objectId, &$objectRef) {
if ($objectName !== 'Contribution' || !$objectRef->id) {
return;
}
try {
$contributionId = $objectRef->id;
if (!$contributionId) {
return;
}
- error_log("contributionId: " . print_r($contributionId, TRUE));
-
if (!empty($objectRef->invoice_id)) {
return;
}
+ // Generate unique invoice ID with proper format
+ $prefix = 'INV';
+ $timestamp = date('YmdHis');
+ $random = substr(md5(uniqid()), 0, 6);
+ $invoiceId = "{$prefix}-{$timestamp}-{$random}";
+
+ // Verify uniqueness
+ $existing = Contribution::get(FALSE)
+ ->addSelect('id')
+ ->addWhere('invoice_id', '=', $invoiceId)
+ ->execute()
+ ->count();
+
+ if ($existing > 0) {
+ throw new \Exception("Generated invoice ID already exists: {$invoiceId}");
+ }
$results = Contribution::update(TRUE)
- ->addValue('invoice_id', 'tarun')
+ ->addValue('invoice_id', $invoiceId)
->addWhere('id', '=', $contributionId)
->execute();
}
catch (\Exception $e) {
\Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [
'Message' => $e->getMessage(),
'Stack Trace' => $e->getTraceAsString(),
]);
}
}Let's verify the uniqueness of invoice IDs:
The previous command had encoding issues. Let's try these alternative approaches to understand the invoice ID generation patterns in the codebase.
The search results show there's existing invoice ID generation logic in the CiviCRM core. Let's examine it to ensure we're following established patterns and not reinventing the wheel.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for duplicate invoice IDs in contributions
ast-grep --pattern $'Contribution::get(FALSE)
->addSelect("invoice_id")
->addWhere("invoice_id", "IS NOT NULL")
->execute()'
Length of output: 9403
Script:
#!/bin/bash
# Let's try a different approach to find invoice ID related code
rg -l "invoice_id" --type php
# Then check for any existing invoice ID generation patterns
rg "invoice.*id.*generate" --type php -i
# Look for contribution related files
fd "contribution" -e php
Length of output: 13144
Script:
#!/bin/bash
# Let's check the existing invoice ID generation logic in Contribution.php
rg -A 10 "invoice_id.*generate" wp-content/plugins/civicrm/civicrm/CRM/Contribute/BAO/Contribution.php
# Also check for any existing invoice ID format patterns
rg "invoice.*format" --type php -i
# Look at the actual implementation in api/v3/Contribution/Transact.php since it was mentioned
rg -A 10 "invoice_id" wp-content/plugins/civicrm/civicrm/api/v3/Contribution/Transact.php
Length of output: 2228
| } | ||
| catch (\Exception $e) { | ||
| \Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [ | ||
| 'Message' => $e->getMessage(), |
There was a problem hiding this comment.
| 'Message' => $e->getMessage(), | |
| 'message' => $e->getMessage(), |
| catch (\Exception $e) { | ||
| \Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [ | ||
| 'Message' => $e->getMessage(), | ||
| 'Stack Trace' => $e->getTraceAsString(), |
There was a problem hiding this comment.
| 'Stack Trace' => $e->getTraceAsString(), | |
| 'trace' => $e->getTraceAsString(), |
| $timestamp = time(); | ||
| // Generate a unique ID based on the current time in microseconds. | ||
| $uniqueId = uniqid(); | ||
| $invoiceId = base64_encode($timestamp . '-' . $uniqueId); |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (1)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (1)
Line range hint
1-1474: Consider splitting the class into focused service classesThe
CollectionCampServiceclass has grown to handle multiple distinct responsibilities:
- Collection camp management
- Email notifications
- Form handling
- Contribution management
This violates the Single Responsibility Principle and makes the code harder to maintain.
Consider splitting into these service classes:
CollectionCampService: Core camp managementCampNotificationService: Email handlingCampFormService: Form operationsContributionService: Contribution and invoice operationsThis would improve:
- Code organization
- Testability
- Maintainability
- Reusability
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php(2 hunks)
🔇 Additional comments (1)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (1)
56-56: LGTM: Event handler registration is correct.
The new event handler is properly registered in the getSubscribedEvents method.
| public static function generateInvoiceIdForContribution(string $op, string $objectName, int $objectId, &$objectRef) { | ||
| if ($objectName !== 'Contribution' || !$objectRef->id) { | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| $contributionId = $objectRef->id; | ||
| if (!$contributionId) { | ||
| return; | ||
| } | ||
|
|
||
| if (!empty($objectRef->invoice_id)) { | ||
| return; | ||
| } | ||
|
|
||
| // Generate a unique invoice ID. | ||
| // Current timestamp. | ||
| $timestamp = time(); | ||
| // Generate a unique ID based on the current time in microseconds. | ||
| $uniqueId = uniqid(); | ||
| $invoiceId = hash('sha256', $timestamp . $uniqueId); | ||
|
|
||
| Contribution::update(TRUE) | ||
| ->addValue('invoice_id', $invoiceId) | ||
| ->addWhere('id', '=', $contributionId) | ||
| ->execute(); | ||
|
|
||
| } | ||
| catch (\Exception $e) { | ||
| \Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [ | ||
| 'Message' => $e->getMessage(), | ||
| 'Stack Trace' => $e->getTraceAsString(), | ||
| ]); | ||
| } | ||
| } |
There was a problem hiding this comment.
💡 Codebase verification
Invoice ID implementation needs alignment with CiviCRM patterns
The current implementation should be updated to match CiviCRM's established patterns:
- Use
md5(uniqid(rand(), TRUE))for invoice ID generation, as consistently shown in CiviCRM core files - While we couldn't find explicit duplicate checks in core, adding one would improve reliability
- Add success logging for better traceability
- Re-throw exceptions to maintain proper error handling chain
- $timestamp = time();
- $uniqueId = uniqid();
- $invoiceId = hash('sha256', $timestamp . $uniqueId);
+ // Use CiviCRM's standard invoice ID generation
+ $invoiceId = md5(uniqid(rand(), TRUE));
+
+ // Add duplicate check for extra safety
+ $existing = Contribution::get(FALSE)
+ ->addSelect('id')
+ ->addWhere('invoice_id', '=', $invoiceId)
+ ->execute()
+ ->count();
+
+ if ($existing > 0) {
+ throw new \Exception("Generated invoice ID already exists: {$invoiceId}");
+ }
Contribution::update(TRUE)
->addValue('invoice_id', $invoiceId)
->addWhere('id', '=', $contributionId)
->execute();
+ \Civi::log()->info("Successfully generated invoice ID for contribution: {$contributionId}");🔗 Analysis chain
Critical: Invoice ID implementation deviates from CiviCRM patterns
The current implementation has several issues:
- The invoice ID generation doesn't follow CiviCRM's established pattern
- No validation for duplicate invoice IDs
- Missing logging for successful generation
- Error logging structure needs improvement
Consider this implementation:
public static function generateInvoiceIdForContribution(string $op, string $objectName, int $objectId, &$objectRef) {
if ($objectName !== 'Contribution' || !$objectRef->id) {
return;
}
try {
$contributionId = $objectRef->id;
if (!$contributionId) {
return;
}
if (!empty($objectRef->invoice_id)) {
return;
}
- // Generate a unique invoice ID.
- // Current timestamp.
- $timestamp = time();
- // Generate a unique ID based on the current time in microseconds.
- $uniqueId = uniqid();
- $invoiceId = hash('sha256', $timestamp . $uniqueId);
+ // Generate invoice ID using CiviCRM's pattern
+ $invoiceId = md5(uniqid(rand(), TRUE));
+
+ // Verify uniqueness
+ $existing = Contribution::get(FALSE)
+ ->addSelect('id')
+ ->addWhere('invoice_id', '=', $invoiceId)
+ ->execute()
+ ->count();
+
+ if ($existing > 0) {
+ throw new \Exception("Generated invoice ID already exists: {$invoiceId}");
+ }
Contribution::update(TRUE)
->addValue('invoice_id', $invoiceId)
->addWhere('id', '=', $contributionId)
->execute();
+ \Civi::log()->info("Successfully generated invoice ID for contribution: {$contributionId}");
}
catch (\Exception $e) {
\Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [
'Message' => $e->getMessage(),
'Stack Trace' => $e->getTraceAsString(),
]);
+ throw $e; // Re-throw to allow proper error handling upstream
}
}Let's verify the CiviCRM invoice ID pattern:
Invoice ID generation pattern matches CiviCRM core implementation
The review comment's suggestion is correct. The search results confirm that CiviCRM consistently uses md5(uniqid(rand(), TRUE)) for invoice ID generation across multiple core components:
CRM/Core/Payment/PayPalProIPN.phpbin/ContributionProcessor.phpapi/v3/Contribution/Transact.php
Let's verify if there are any existing duplicate invoice ID checks:
Let's try a different search pattern to find duplicate invoice ID validation:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for existing invoice ID generation patterns
rg -A 5 "invoice_id.*=.*md5" --type php
Length of output: 2130
Script:
#!/bin/bash
# Search for duplicate invoice ID validation patterns
rg -B 2 -A 5 "invoice_id.*=.*" --type php | rg -B 2 -A 5 "count|exist"
Length of output: 72
Script:
#!/bin/bash
# Search for invoice ID uniqueness checks in a broader context
rg -B 5 -A 5 "addWhere.*invoice_id.*=" --type php
Length of output: 51
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (1)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (1)
1440-1474: Add success logging for better traceability.Consider adding a success log message after successful invoice ID generation for better traceability.
->addWhere('id', '=', $contributionId) ->execute(); + \Civi::log()->info("Successfully generated invoice ID for contribution: {$contributionId}"); } catch (\Exception $e) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php(2 hunks)
🔇 Additional comments (2)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (2)
56-56: LGTM: Hook registration is properly configured.
The new hook for invoice ID generation is correctly registered in the post-write event handlers.
1455-1461:
Critical: Invoice ID generation needs alignment with CiviCRM patterns.
The current implementation should be updated to match CiviCRM's established patterns:
- Use
md5(uniqid(rand(), TRUE))for invoice ID generation - Add duplicate check for reliability
- // Generate a unique invoice ID.
- // Current timestamp.
- $timestamp = time();
- // Generate a unique ID based on the current time in microseconds.
- $uniqueId = uniqid();
- $invoiceId = hash('sha256', $timestamp . $uniqueId);
+ // Generate invoice ID using CiviCRM's pattern
+ $invoiceId = md5(uniqid(rand(), TRUE));
+
+ // Verify uniqueness
+ $existing = Contribution::get(FALSE)
+ ->addSelect('id')
+ ->addWhere('invoice_id', '=', $invoiceId)
+ ->execute()
+ ->count();
+
+ if ($existing > 0) {
+ throw new \Exception("Generated invoice ID already exists: {$invoiceId}");
+ }Likely invalid or redundant comment.
| catch (\Exception $e) { | ||
| \Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [ | ||
| 'message' => $e->getMessage(), | ||
| 'trace' => $e->getTraceAsString(), | ||
| ]); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve error handling and logging consistency.
- Re-throw the exception to maintain proper error handling chain
- Use consistent log message keys (Message/Stack Trace) as seen in other methods
catch (\Exception $e) {
\Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [
- 'message' => $e->getMessage(),
- 'trace' => $e->getTraceAsString(),
+ 'Message' => $e->getMessage(),
+ 'Stack Trace' => $e->getTraceAsString(),
]);
+ throw $e; // Re-throw to allow proper error handling upstream
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| catch (\Exception $e) { | |
| \Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [ | |
| 'message' => $e->getMessage(), | |
| 'trace' => $e->getTraceAsString(), | |
| ]); | |
| } | |
| catch (\Exception $e) { | |
| \Civi::log()->error("Exception occurred in generateInvoiceIdForContribution.", [ | |
| 'Message' => $e->getMessage(), | |
| 'Stack Trace' => $e->getTraceAsString(), | |
| ]); | |
| throw $e; // Re-throw to allow proper error handling upstream | |
| } |
Autogenerate Invoice ID when we are adding contribution from backend
Summary by CodeRabbit
Summary by CodeRabbit