Fix submit handling of thousands when creating data entry batch
[civicrm-core.git] / CRM / Batch / BAO / EntityBatch.php
index 025a877b8ec3965e28524984c45c5001335fedfd..f4c1e55a7027fc5e49ee220c13804bde98fb29c0 100644 (file)
@@ -23,6 +23,35 @@ class CRM_Batch_BAO_EntityBatch extends CRM_Batch_DAO_EntityBatch {
    * @return CRM_Batch_DAO_EntityBatch
    */
   public static function create($params) {
+    // Only write the EntityBatch record if the financial trxn and batch match on currency and payment instrument.
+    $batchId = $params['batch_id'] ?? NULL;
+    $entityId = $params['entity_id'] ?? NULL;
+    // Not having a batch ID and entity ID is only acceptable on an update.
+    if (!$batchId) {
+      $existingEntityBatch = \Civi\Api4\EntityBatch::get(FALSE)
+        ->addSelect('id', '=', $params['id'])
+        ->execute()
+        ->first();
+      $batchId = $existingEntityBatch['batch_id'] ?? NULL;
+      $entityId = $existingEntityBatch['entity_id'] ?? NULL;
+    }
+    // There should never be a legitimate case where a record has an ID but no batch ID but SyntaxConformanceTest says otherwise.
+    if ($batchId) {
+      $batchCurrency = self::getBatchCurrency($batchId);
+      $batchPID = (int) CRM_Core_DAO::getFieldValue('CRM_Batch_DAO_Batch', $batchId, 'payment_instrument_id');
+      $trxn = \Civi\Api4\FinancialTrxn::get(FALSE)
+        ->addSelect('currency', 'payment_instrument_id')
+        ->addWhere('id', '=', $entityId)
+        ->execute()
+        ->first();
+      if ($batchCurrency && $batchCurrency !== $trxn['currency']) {
+        throw new \CRM_Core_Exception(ts('You can not add items of two different currencies to a single contribution batch.'));
+      }
+      if ($batchPID && $trxn && $batchPID !== $trxn['payment_instrument_id']) {
+        $paymentInstrument = CRM_Core_PseudoConstant::getLabel('CRM_Batch_BAO_Batch', 'payment_instrument_id', $batchPID);
+        throw new \CRM_Core_Exception(ts('This batch is configured to include only transactions using %1 payment method. If you want to include other transactions, please edit the batch first and modify the Payment Method.', [1 => $paymentInstrument]));
+      }
+    }
     return self::writeRecord($params);
   }
 
@@ -39,4 +68,28 @@ class CRM_Batch_BAO_EntityBatch extends CRM_Batch_DAO_EntityBatch {
     return self::deleteRecord($params);
   }
 
+  /**
+   * Get the currency associated with a batch (if any).
+   *
+   * @param int $batchId
+   *
+   */
+  public static function getBatchCurrency($batchId) : ?string {
+    $sql = "SELECT DISTINCT ft.currency
+      FROM  civicrm_batch batch
+      JOIN civicrm_entity_batch eb
+        ON batch.id = eb.batch_id
+      JOIN civicrm_financial_trxn ft
+        ON eb.entity_id = ft.id
+      WHERE batch.id = %1";
+    $dao = CRM_Core_DAO::executeQuery($sql, [1 => [$batchId, 'Positive']]);
+    if ($dao->N === 0) {
+      return NULL;
+    }
+    else {
+      $dao->fetch();
+      return $dao->currency;
+    }
+  }
+
 }