From a58790289b9dbfad388a1976f07cee5336ca8d95 Mon Sep 17 00:00:00 2001
From: Christian Spitzlay <christian.spitzlay@bio.logis.de>
Date: Mon, 10 Sep 2012 18:24:24 +0200
Subject: [PATCH 1/2] implement new callback-based method for invoice number
 generation see also: http://drupal.org/node/1728106

---
 commerce_invoice.module                   |  4 ++++
 commerce_invoice_ui.info                  |  1 +
 includes/commerce_invoice.controller.inc  | 16 +++++++++++++--
 includes/commerce_invoice_ui.invoices.inc | 34 +++++++++++++++++++++++++++++--
 4 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/commerce_invoice.module b/commerce_invoice.module
index dbd631a..4e3f773 100644
--- a/commerce_invoice.module
+++ b/commerce_invoice.module
@@ -17,6 +17,10 @@ define('COMMERCE_INVOICE_METHOD_YEAR', 'Y-[invoice_id]');
 // Invoice id is regenerated every month
 define('COMMERCE_INVOICE_METHOD_MONTH', 'Y-m-[invoice_id]');
 
+// Invoice number is generated by a callback that is being passed the invoice object
+define('COMMERCE_INVOICE_METHOD_CALLBACK', 'callback');
+
+
 /**
  * Implements hook_entity_info().
  */
diff --git a/commerce_invoice_ui.info b/commerce_invoice_ui.info
index fe5fc3d..26dfaa7 100644
--- a/commerce_invoice_ui.info
+++ b/commerce_invoice_ui.info
@@ -8,4 +8,5 @@ dependencies[] = field_ui
 dependencies[] = commerce
 dependencies[] = commerce_ui
 dependencies[] = commerce_invoice
+dependencies[] = ctools
 dependencies[] = views
diff --git a/includes/commerce_invoice.controller.inc b/includes/commerce_invoice.controller.inc
index 443b519..3f48d52 100644
--- a/includes/commerce_invoice.controller.inc
+++ b/includes/commerce_invoice.controller.inc
@@ -53,7 +53,7 @@ class CommerceInvoiceEntityController extends DrupalCommerceEntityController {
       // Inserting new invoice
       if (empty($invoice->invoice_id)) {
         $invoice->created = REQUEST_TIME;
-        $invoice->invoice_number = $this->generate_invoice_id();
+        $invoice->invoice_number = $this->generate_invoice_id($invoice);
 
         $this->invoke('presave', $invoice);
         $invoice = $this->_save($invoice, $transaction);
@@ -112,10 +112,12 @@ class CommerceInvoiceEntityController extends DrupalCommerceEntityController {
   /**
    * Generates invoice id
    *
+   * @param object $invoice The invoice to generate an invoice number for.
+   *
    * @return
    *   The generated invoice id
    */
-  protected function generate_invoice_id() {
+  protected function generate_invoice_id($invoice) {
     // TODO: there is probably a better way to do this
     // Invoice generation method
     $method = variable_get('commerce_invoice_number_method', COMMERCE_INVOICE_METHOD_YEAR);
@@ -170,6 +172,16 @@ class CommerceInvoiceEntityController extends DrupalCommerceEntityController {
           }
           $return = date('Y') . '-' . date('m') . '-' . $id;
           break;
+        case COMMERCE_INVOICE_METHOD_CALLBACK:
+          $function_name = variable_get('commerce_invoice_number_callback', '');
+          if (empty($function_name) || !function_exists($function_name)) {
+            drupal_set_message(t('No valid callback defined for invoice number generation.'), 'error');
+            $return = t('no-invoice-number');
+          }
+          else {
+            $return = $function_name($invoice);
+          }
+          break;
       }
       return $return;
 
diff --git a/includes/commerce_invoice_ui.invoices.inc b/includes/commerce_invoice_ui.invoices.inc
index a72861e..9a1653e 100644
--- a/includes/commerce_invoice_ui.invoices.inc
+++ b/includes/commerce_invoice_ui.invoices.inc
@@ -18,9 +18,39 @@ function commerce_invoice_settings_form($form, &$form_state) {
     '#options' => array(
       COMMERCE_INVOICE_METHOD_INFINITE => t('Infinite (one single number, that is never reset, and incremented at each invoice generation)'),
       COMMERCE_INVOICE_METHOD_YEAR => t('Reset every year, with an id incremented at each invoice generation (@invoice_number)', array('@invoice_number' => date('Y').'-[invoice_id]')),
-      COMMERCE_INVOICE_METHOD_MONTH => t('Reset every month, with an id incremented at each invoice generation (@invoice_number)', array('@invoice_number' => date('Y-m').'-[invoice_id]'))
-    )
+      COMMERCE_INVOICE_METHOD_MONTH => t('Reset every month, with an id incremented at each invoice generation (@invoice_number)', array('@invoice_number' => date('Y-m').'-[invoice_id]')),
+      COMMERCE_INVOICE_METHOD_CALLBACK => t('Invoice number generation is controlled by a callback function that is being passed the invoice object')
+    ),
+  );
+
+  $callbacks = module_invoke_all('commerce_invoice_number_callbacks');
+  $options = array_combine($callbacks, $callbacks);
+
+  $form['commerce_invoice_number_callback'] = array(
+    '#type' => 'select',
+    '#title' => t('Invoice number creation callback'),
+    '#description' => t('This selects the callback function for the callback method.'),
+    '#default_value' => variable_get('commerce_invoice_number_callback', ''),
+    '#options' => $options,
+    '#element_validate' => array('commerce_invoice_ui_validate_invoice_number_callback'),
+    '#states' => array(
+      'visible' => array(
+        ':input[name="commerce_invoice_number_method"]' => array('value' => COMMERCE_INVOICE_METHOD_CALLBACK),
+      ),
+    ),
   );
 
   return system_settings_form($form);
 }
+
+function commerce_invoice_ui_validate_invoice_number_callback($element, &$form_state, $form) {
+  if ($form_state['values']['commerce_invoice_number_method'] == COMMERCE_INVOICE_METHOD_CALLBACK) {
+    if (empty($form_state['values']['commerce_invoice_number_callback'])) {
+      form_set_error('commerce_invoice_number_callback', t('Please specify a callback function.'));
+    }
+    elseif (!function_exists($form_state['values']['commerce_invoice_number_callback'])) {
+      form_set_error('commerce_invoice_number_callback', t('"@callback" is not a valid callback function.', array('@callback' => $form_state['values']['commerce_invoice_number_callback'])));
+    }
+  }
+}
+
-- 
1.7.12


From 9951b06dbb96605936fac7458bc2463f54b84394 Mon Sep 17 00:00:00 2001
From: Christian Spitzlay <christian.spitzlay@bio.logis.de>
Date: Wed, 12 Sep 2012 11:27:17 +0200
Subject: [PATCH 2/2] move transaction boundaries so they include invoice
 number generation

---
 commerce_invoice_ui.info                 |  1 -
 includes/commerce_invoice.controller.inc | 36 +++++++++++++-------------------
 2 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/commerce_invoice_ui.info b/commerce_invoice_ui.info
index 26dfaa7..fe5fc3d 100644
--- a/commerce_invoice_ui.info
+++ b/commerce_invoice_ui.info
@@ -8,5 +8,4 @@ dependencies[] = field_ui
 dependencies[] = commerce
 dependencies[] = commerce_ui
 dependencies[] = commerce_invoice
-dependencies[] = ctools
 dependencies[] = views
diff --git a/includes/commerce_invoice.controller.inc b/includes/commerce_invoice.controller.inc
index 3f48d52..906e4b5 100644
--- a/includes/commerce_invoice.controller.inc
+++ b/includes/commerce_invoice.controller.inc
@@ -47,6 +47,7 @@ class CommerceInvoiceEntityController extends DrupalCommerceEntityController {
    *   The saved invoice object.
    */
   public function save($invoice, DatabaseTransaction $transaction = NULL) {
+    $transaction = !is_null($transaction) ? $transaction : db_transaction();
     try {
       $invoice->changed = REQUEST_TIME;
 
@@ -68,6 +69,8 @@ class CommerceInvoiceEntityController extends DrupalCommerceEntityController {
       return $invoice;
     }
     catch (Exception $e) {
+      $transaction->rollback();
+      watchdog_exception('commerce_invoice', $e);
       throw $e;
     }
   }
@@ -84,29 +87,20 @@ class CommerceInvoiceEntityController extends DrupalCommerceEntityController {
    *   The saved invoice object.
    */
   private function _save($invoice, DatabaseTransaction $transaction = NULL) {
-    $transaction = isset($transaction) ? $transaction : db_transaction();
-    try {
-      if (empty($invoice->invoice_id)) {
-        // Save the new invoice
-        drupal_write_record('commerce_invoice', $invoice);
-        field_attach_insert('commerce_invoice', $invoice);
-      }
-      else {
-        drupal_write_record('commerce_invoice', $invoice, 'invoice_id');
-        field_attach_update('commerce_invoice', $invoice);
-      }
-      // Ignore slave server temporarily to give time for the
-      // saved invoice to be propagated to the slave.
-      db_ignore_slave();
-
-
-      return $invoice;
+    if (empty($invoice->invoice_id)) {
+      // Save the new invoice
+      drupal_write_record('commerce_invoice', $invoice);
+      field_attach_insert('commerce_invoice', $invoice);
     }
-    catch (Exception $e) {
-      $transaction->rollback();
-      watchdog_exception('commerce_invoice', $e);
-      throw $e;
+    else {
+      drupal_write_record('commerce_invoice', $invoice, 'invoice_id');
+      field_attach_update('commerce_invoice', $invoice);
     }
+    // Ignore slave server temporarily to give time for the
+    // saved invoice to be propagated to the slave.
+    db_ignore_slave();
+
+    return $invoice;
   }
 
   /**
-- 
1.7.12

