Transaction references extended with parametrized patterns, added check_reference...
authorJanusz Dobrowolski <janusz@frontaccounting.eu>
Wed, 18 Feb 2015 12:13:33 +0000 (13:13 +0100)
committerJanusz Dobrowolski <janusz@frontaccounting.eu>
Mon, 20 Apr 2015 11:39:03 +0000 (13:39 +0200)
58 files changed:
admin/db/fiscalyears_db.inc
admin/db/transactions_db.inc
admin/forms_setup.php
applications/setup.php
dimensions/dimension_entry.php
gl/bank_transfer.php
gl/gl_bank.php
gl/gl_journal.php
gl/includes/db/gl_db_banking.inc
gl/includes/db/gl_db_trans.inc
gl/includes/ui/gl_bank_ui.inc
gl/manage/revaluate_currencies.php
includes/data_checks.inc
includes/db/class.data_set.inc [new file with mode: 0644]
includes/db/class.reflines_db.inc [new file with mode: 0644]
includes/db/inventory_db.inc
includes/db/references_db.inc [deleted file]
includes/references.inc
includes/ui/class.crud_view.inc [new file with mode: 0644]
includes/ui/class.reflines_crud.inc [new file with mode: 0644]
includes/ui/ui_input.inc
includes/ui/ui_lists.inc
includes/ui/ui_view.inc
inventory/adjustments.php
inventory/includes/item_adjustments_ui.inc
inventory/includes/stock_transfers_ui.inc
inventory/transfers.php
manufacturing/includes/db/work_order_costing_db.inc
manufacturing/includes/work_order_issue_ui.inc
manufacturing/work_order_add_finished.php
manufacturing/work_order_costs.php
manufacturing/work_order_entry.php
manufacturing/work_order_issue.php
purchasing/includes/db/invoice_db.inc
purchasing/includes/purchasing_db.inc
purchasing/includes/ui/grn_ui.inc
purchasing/includes/ui/invoice_ui.inc
purchasing/includes/ui/po_ui.inc
purchasing/po_entry_items.php
purchasing/po_receive_items.php
purchasing/supplier_credit.php
purchasing/supplier_invoice.php
purchasing/supplier_payment.php
sales/create_recurrent_invoices.php
sales/credit_note_entry.php
sales/customer_credit_invoice.php
sales/customer_delivery.php
sales/customer_invoice.php
sales/customer_payments.php
sales/includes/cart_class.inc
sales/includes/db/sales_invoice_db.inc
sales/includes/db/sales_order_db.inc
sales/includes/ui/sales_credit_ui.inc
sales/includes/ui/sales_order_ui.inc
sales/sales_order_entry.php
sql/alter2.4.sql
sql/en_US-demo.sql
sql/en_US-new.sql

index 9051e47547faa3e49f84f1e0754b59dbb39605f7..f9b4d415181edc98a2a0bed25e1e982a3dab3312 100644 (file)
@@ -160,7 +160,7 @@ function close_year($year)
        if ($balance != 0.0)
        {
                $cart = new items_cart(ST_JOURNAL);
-               $cart->reference = $Refs->get_next(ST_JOURNAL, null, $to);
+               $cart->reference = $Refs->get_next(ST_JOURNAL, null, sql2date($to));
                $cart->tran_date = $cart->doc_date = $cart->event_date = $to;
 
                $cart->add_gl_item($co['retained_earnings_act'], 0, 0, -$balance, _("Closing Year"), '', 0);
@@ -372,6 +372,7 @@ function delete_this_fiscalyear($selected_id)
                $trans_type = ST_JOURNAL;
                $date_ = sql2date($to);
                $reference = $Refs->get_next($trans_type, null, $date_);
+               $Refs->save($trans_type, $trans_no, $reference);
                add_journal($trans_type, $trans_no, $total, $date_, get_company_currency(), $reference);
                $Refs->save($trans_type, $trans_no, $reference);
                add_audit_trail($trans_type, $trans_no, $date_);
index d3e3cfc5626b1c6b64e9976b186a48199a0384be..d343b7c4ba8522119d1e93688bd73101ff4d4244 100644 (file)
@@ -36,8 +36,6 @@ function get_sql_for_view_transactions($filtertype, $from, $to, &$trans_ref)
                $sql .= ", t.$type_name as type";
        $sql .= " FROM $table_name t LEFT JOIN ".TB_PREF."voided v ON"
                ." t.$trans_no_name=v.id AND v.type=$filtertype";
-       if (!$trans_ref)
-               $sql .= " LEFT JOIN ".TB_PREF."refs r ON t.$trans_no_name=r.id AND r.type=$filtertype";
 
        $sql .= " WHERE ISNULL(v.`memo_`)";
        if ($from != null && $to != null)
@@ -209,16 +207,8 @@ function get_systype_db_info($type)
         case     31              : return array(TB_PREF."service_orders", null, "order_no", "cust_ref", "date");
         case     ST_SALESQUOTE   : return array(TB_PREF."sales_orders", "trans_type", "order_no", "reference", "ord_date");
         case    ST_DIMENSION    : return array(TB_PREF."dimensions", null, "id", "reference", "date_");
-        case     ST_COSTUPDATE   : return array(TB_PREF."gl_trans", "type", "type_no", null, "tran_date");
+        case     ST_COSTUPDATE   : return array(TB_PREF."journal", "type", "trans_no", "reference", "tran_date");
        }
 
        display_db_error("invalid type ($type) sent to get_systype_db_info", "", true);
 }
-
-function get_systypes()
-{
-       $sql = "SELECT * FROM ".TB_PREF."sys_types";
-       $result = db_query($sql, "could not query systypes table");
-       return $result;
-}
-
index 5a91d31e8559fc4865906ad4b6bdd51e5db495da..a2895ab63c6c6bddc08638c74fc7bb0275d6db68 100644 (file)
     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
 ***********************************************************************/
 $page_security = 'SA_FORMSETUP';
-$path_to_root = "..";
-include($path_to_root . "/includes/session.inc");
+$path_to_root="..";
 
-page(_($help_context = "Forms Setup"));
+include_once($path_to_root . "/includes/session.inc");
+include_once('../includes/ui/class.reflines_crud.inc');
 
-include($path_to_root . "/includes/ui.inc");
+include_once($path_to_root . "/includes/ui.inc");
 
-//-------------------------------------------------------------------------------------------------
-
-if (isset($_POST['setprefs'])) 
-{
-
-       $systypes = get_systypes();
-
-       begin_transaction();
-
-    while ($type = db_fetch($systypes)) 
-    {
-       save_next_reference($type["type_id"], $_POST['id' . $type["type_id"]]);
-    }
-
-    commit_transaction();
-
-       display_notification_centered(_("Forms settings have been updated."));
-}
+page(_($help_context = "Transaction References"));
 
 start_form();
 
-start_outer_table(TABLESTYLE2);
-
-$systypes = get_systypes();
-table_section(1);
-
-$th = array(_("Form"), _("Next Reference"));
-table_header($th);
-$i = 0;
-while ($type = db_fetch($systypes)) 
-{
-       if ($i++ == ST_CUSTCREDIT)
-       {
-               table_section(2);
-               table_header($th);
-       }       
-       ref_row($systypes_array[$type["type_id"]], 'id' . $type["type_id"], '', $type["next_reference"]);
-}
-
-end_outer_table(1);
-
-submit_center('setprefs', _("Update"), true, '', 'default');
-
-end_form(2);
+$companies = new fa_reflines();
 
-//-------------------------------------------------------------------------------------------------
+$companies->show();
 
-end_page();
+end_form();
 
+end_page();
\ No newline at end of file
index e29817be5108d5f1dbfabf259516aa93f064a7dd..99fa48d52b9278a59808eeec49d96d28039274ec 100644 (file)
@@ -24,7 +24,7 @@ class setup_app extends application
                        "admin/security_roles.php?", 'SA_SECROLES', MENU_SETTINGS);
                $this->add_lapp_function(0, _("&Display Setup"),
                        "admin/display_prefs.php?", 'SA_SETUPDISPLAY', MENU_SETTINGS);
-               $this->add_lapp_function(0, _("&Forms Setup"),
+               $this->add_lapp_function(0, _("Transaction &References"),
                        "admin/forms_setup.php?", 'SA_FORMSETUP', MENU_SETTINGS);
                $this->add_rapp_function(0, _("&Taxes"),
                        "taxes/tax_types.php?", 'SA_TAXRATES', MENU_MAINTENANCE);
index 7809bd1bb2f397307c936c4881302145849f8f5a..f46be106cc12e50b266030a63fe69759cc6cba77 100644 (file)
@@ -109,17 +109,8 @@ function can_process()
 
        if ($selected_id == -1) 
        {
-
-       if (!$Refs->is_valid($_POST['ref'])) 
-       {
-               display_error( _("The dimension reference must be entered."));
-                       set_focus('ref');
-               return false;
-       }
-
-       if (!is_new_reference($_POST['ref'], ST_DIMENSION)) 
+       if (!check_reference($_POST['ref'], ST_DIMENSION))
        {
-               display_error(_("The entered reference is already in use."));
                        set_focus('ref');
                return false;
        }
@@ -264,7 +255,7 @@ if ($selected_id != -1)
 else 
 {
        $_POST['dimension_tags'] = array();
-       ref_row(_("Dimension Reference:"), 'ref', '', $Refs->get_next(ST_DIMENSION));
+       ref_row(_("Dimension Reference:"), 'ref', '', $Refs->get_next(ST_DIMENSION), false, ST_DIMENSION);
 }
 
 text_row_ex(_("Name") . ":", 'name', 50, 75);
index 7b987636a16162d005e06a133bba6b247720013e..3ebc24535a6947c6fabf46254c93d27706ece656 100644 (file)
@@ -87,7 +87,7 @@ function gl_payment_controls($trans_no)
                        $_POST['target_amount'] = price_format($to_trans['amount']);
                        $_POST['amount'] = price_format(-$from_trans['amount']);
                } else {
-                       $_POST['ref'] = $Refs->get_next(ST_BANKTRANSFER);
+                       $_POST['ref'] = $Refs->get_next(ST_BANKTRANSFER, null, get_post('DatePaid'));
                        $_POST['memo_'] = '';
                        $_POST['FromBankAccount'] = 0;
                        $_POST['ToBankAccount'] = 0;
@@ -115,7 +115,8 @@ function gl_payment_controls($trans_no)
        }
     date_row(_("Transfer Date:"), 'DatePaid', '', true, 0, 0, 0, null, true);
 
-       ref_row(_("Reference:"), 'ref', '', $_POST['ref']);
+    ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_BANKTRANSFER, null, get_post('DatePaid')), false, ST_BANKTRANSFER,
+       array('date' => get_post('DatePaid')));
 
        table_section(2);
 
@@ -232,15 +233,8 @@ function check_valid_entries($trans_no)
                set_focus('charge');
                return false;
        }
-       if (!$Refs->is_valid($_POST['ref'])) 
-       {
-               display_error(_("You must enter a reference."));
-               set_focus('ref');
-               return false;
-       }
 
-       if (! $trans_no && ! is_new_reference($_POST['ref'], ST_BANKTRANSFER)) {
-               display_error(_("The entered reference is already in use."));
+       if (!check_reference($_POST['ref'], ST_BANKTRANSFER, $trans_no)) {
                set_focus('ref');
                return false;
        }
index b965f1d50aefa0a8e05945d262111153d712bf53..3d3f86e64e33643671549e348713a60ad0a0e7fd 100644 (file)
@@ -153,7 +153,8 @@ function create_cart($type, $trans_no)
                $bank_trans = db_fetch(get_bank_trans($type, $trans_no));
                $_POST['bank_account'] = $bank_trans["bank_act"];
                $_POST['PayType'] = $bank_trans["person_type_id"];
-               
+               $cart->reference = $bank_trans["ref"];
+
                if ($bank_trans["person_type_id"] == PT_CUSTOMER)
                {
                        $trans = get_customer_trans($trans_no, $type);  
@@ -174,7 +175,6 @@ function create_cart($type, $trans_no)
 
                $cart->memo_ = get_comments_string($type, $trans_no);
                $cart->tran_date = sql2date($bank_trans['trans_date']);
-               $cart->reference = $Refs->get($type, $trans_no);
 
                $cart->original_amount = $bank_trans['amount'];
                $result = get_gl_trans($type, $trans_no);
@@ -197,7 +197,7 @@ function create_cart($type, $trans_no)
                        $cart->gl_items[$line_no]->amount *= $ex_rate;
 
        } else {
-               $cart->reference = $Refs->get_next($cart->trans_type);
+               $cart->reference = $Refs->get_next($cart->trans_type, null, $cart->tran_date);
                $cart->tran_date = new_doc_date();
                if (!is_date_in_fiscalyear($cart->tran_date))
                        $cart->tran_date = end_fiscalyear();
@@ -246,15 +246,8 @@ function check_trans()
                set_focus('amount');
                $input_error = 1;
        }
-       if (!$Refs->is_valid($_POST['ref']))
-       {
-               display_error( _("You must enter a reference."));
-               set_focus('ref');
-               $input_error = 1;
-       }
-       elseif ($_POST['ref'] != $_SESSION['pay_items']->reference && !is_new_reference($_POST['ref'], $_SESSION['pay_items']->trans_type))
+       if (!check_reference($_POST['ref'], $_SESSION['pay_items']->trans_type, $_SESSION['pay_items']->order_id))
        {
-               display_error( _("The entered reference is already in use."));
                set_focus('ref');
                $input_error = 1;
        }
index f2defddc161e8c2ab761d1c98de6d11d50f9bf79..e057d0989563d63c01369e20b4a17b4bbf7bca64 100644 (file)
@@ -130,8 +130,6 @@ function create_cart($type=0, $trans_no=0)
                $cart->memo_ = get_comments_string($type, $trans_no);
                $cart->reference = $header['reference'];
 
-               $_POST['ref_original'] = $cart->reference; // Store for comparison when updating
-
                // update net_amounts from tax register
 
                // retrieve tax details
@@ -164,7 +162,6 @@ function create_cart($type=0, $trans_no=0)
                if (!is_date_in_fiscalyear($cart->tran_date))
                        $cart->tran_date = end_fiscalyear();
                $cart->reference = $Refs->get_next(ST_JOURNAL, null, $cart->tran_date);
-               $_POST['ref_original'] = -1;
        }
 
        $_POST['memo_'] = $cart->memo_;
@@ -239,15 +236,8 @@ if (isset($_POST['Process']))
                set_focus('doc_date');
                $input_error = 1;
        }
-       if (!$Refs->is_valid($_POST['ref'])) 
-       {
-               display_error( _("You must enter a reference."));
-               set_focus('ref');
-               $input_error = 1;
-       } 
-       elseif (($_POST['ref'] != $_POST['ref_original']) && $Refs->exists(ST_JOURNAL,$_POST['ref'])) 
+       if (!check_reference($_POST['ref'], ST_JOURNAL, $_SESSION['journal_items']->order_id))
        {
-               display_error( _("The entered reference is already in use."));
                set_focus('ref');
                $input_error = 1;
        }
index 9d5b9693879dd70ecaf61f00b735f7a0a37a6b9b..095dadcd9028d97b90bec7491f1205a1ccaf2efc 100644 (file)
@@ -156,7 +156,7 @@ function add_exchange_variation_all($date=null, $ref="", $memo)
        {
                add_comments(ST_JOURNAL, $trans_no, $date, $memo);
                if ($ref == "")
-                       $ref = $Refs->get_next(ST_JOURNAL);
+                       $ref = $Refs->get_next(ST_JOURNAL, null, $date);
                $Refs->save(ST_JOURNAL, $trans_no, $ref);
                add_audit_trail(ST_JOURNAL, $trans_no, $date);
        }       
@@ -288,7 +288,7 @@ function add_bank_transfer($from_account, $to_account, $date_,
        }
        if ($exchanged == true)
        {
-               $ref1 = $Refs->get_next(ST_JOURNAL);
+               $ref1 = $Refs->get_next(ST_JOURNAL, null, $date_);
                $Refs->save(ST_JOURNAL, $trans_no1, $ref1);
                add_audit_trail(ST_JOURNAL, $trans_no1, $date_);
        }
@@ -525,7 +525,7 @@ function write_bank_transaction($trans_type, $trans_no, $from_account, $items, $
        if ($exchanged || add_exchange_variation($trans_no1, $date_, $from_account, $bank_gl_account, 
                $currency, $person_type_id, $person_id))
        {
-                       $ref1 = $Refs->get_next(ST_JOURNAL);
+                       $ref1 = $Refs->get_next(ST_JOURNAL, null, $date_);
                        $Refs->save(ST_JOURNAL, $trans_no1, $ref1);
                        add_audit_trail(ST_JOURNAL, $trans_no1, $date_);
                }
index c4fff50c1c77418a2241ce62b610c074d70460a6..40187bb2845a8429291f4178cf602c6804722051 100644 (file)
@@ -515,6 +515,7 @@ function get_tax_summary($from, $to, $also_zero_purchases=false)
                // display_error($sql);
     return db_query($sql,"Cannot retrieve tax summary");
 }
+
 //--------------------------------------------------------------------------------------------------
 
 function exists_gl_trans($type, $trans_id)
index ce3af74afa6db9b6c985fc2669fc529bc2a9dfe1..8e491712a03d52cf19cfa51953c190d3db5d46d4 100644 (file)
@@ -23,7 +23,7 @@ function display_bank_header(&$order)
        
     date_row(_("Date:"), 'date_', '', true, 0, 0, 0, null, true);
 
-       ref_row(_("Reference:"), 'ref', '');
+       ref_row(_("Reference:"), 'ref', '', $order->reference, false, $order->trans_type, get_post('date_'));
 
        table_section(2, "33%");
 
index c05237ac9e72ca63db5a39a9351c895d04e7dd63..f01414186402930604d8708593b583718a63de03 100644 (file)
@@ -60,16 +60,8 @@ function check_data()
                set_focus('date');
                return false;
        }
-       if (!$Refs->is_valid($_POST['ref'])) 
+       if (!check_reference($_POST['ref'], ST_JOURNAL))
        {
-               display_error(_("You must enter a reference."));
-               set_focus('ref');
-               return false;
-       }
-
-       if (!is_new_reference($_POST['ref'], ST_JOURNAL)) 
-       {
-               display_error(_("The entered reference is already in use."));
                set_focus('ref');
                return false;
        }
@@ -102,7 +94,7 @@ function display_reval()
        if (!isset($_POST['date']))
                $_POST['date'] = Today();
     date_row(_("Date for Revaluation:"), 'date', '', null, 0, 0, 0, null, true);
-    ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_JOURNAL));
+    ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_JOURNAL, null, $_POST['date']), false, ST_JOURNAL);
     textarea_row(_("Memo:"), 'memo_', null, 40,4);
        end_table(1);
 
index 7ce8d668adced13db154009c9bca372e8d77edc6..7243e43fe937be460c3650d47028ade5939d7a33 100644 (file)
@@ -524,3 +524,17 @@ function check_is_editable($trans_type, $trans_no, $msg=null)
                check_is_closed($trans_type, $trans_no, $msg);
 }
 
+function check_reference($reference, $trans_type, $trans_no=0, $context=null, $line=null)
+{
+       global $Refs;
+
+       if (!$Refs->is_valid($reference, $trans_type, $context, $line))
+       {
+               display_error(_("The entered reference is invalid.")); return false;
+       }
+       elseif (!$Refs->is_new_reference($reference, $trans_type, $trans_no))
+       {
+               display_error( _("The entered reference is already in use.")); return false;
+       }
+       return true;
+}
diff --git a/includes/db/class.data_set.inc b/includes/db/class.data_set.inc
new file mode 100644 (file)
index 0000000..f536e13
--- /dev/null
@@ -0,0 +1,518 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+
+// array contains optional/required params for all supported validator types
+// 
+$validator_types = array(
+       'required' => array(),
+       'range' => array('min'=>0, 'max' =>null, 'lt', 'gt', 'le', 'ge')
+);
+
+/*
+       Generic record set object
+*/
+abstract class record_set {
+       var $key;                       // unique key fields
+       var $fields;            // other fields
+       var $name;                      // table name (without prefix)
+       var $checks = array();          // checks on data before insert/update/delete
+
+       var $selected_id;       // current key
+       var $data;                      // current record data
+       var $errors = array();
+       var $debug = array();
+       var $subset;            // optional where clause for record subset
+
+       function __wakeup()
+       {
+               $this->errors = array();
+       }
+
+       function record_set($name, $fields, $key, $subset=null)
+       {
+               $this->name = $name;
+               $this->fields = $fields;
+               $this->key = $key;
+               $this->subset = $subset;
+       }
+
+       function error($msg, $field=null) {
+               global $db;
+
+               // save error message
+               if (!isset($field))
+                       $field = count($this->errors);
+               $this->errors[$field] = $msg;
+
+               // save db errors for debugging purposes
+               if ($db && db_error_no()) $this->debug[] = db_error_msg($db);
+
+               return false;
+       }
+       //==============================================================================================
+       // 
+       // Data valiation
+
+       /**
+       *       Set validator for insert/update/delete
+       *
+       *       @check - validator description string in format: 'field_name:uid_modes:check_type[[:param1][:param2]...]'
+       *   parameters can be expressed with name in form: name=value
+       *       @msg - message stored on error
+       **/
+       
+       function set_validator($check, $msg=null)
+       {
+               $params = explode(':', $check);
+               if (count($params)<3)
+                       display_error(_('Invalid validator string'));
+
+               $fieldname = array_shift($params);
+               $mode = array_shift($params);
+               $type = array_shift($params);
+               $options = array();
+               if (count($params))
+               {
+                       foreach ($params as $par) {
+                               if (($n = strpos($par, '=')) !== false) {
+                                       $options[substr($par, 0, $n)] = substr($par, $n+1);
+                               } else
+                                       $options[] = $par;
+                       }
+               }
+               $this->checks[] = array('fld'=>$fieldname, 'type' => $type, 'msg' => $msg, 'opts' => $options, 'mode'=>$mode);
+       }
+
+       /**
+       *       Validate data
+       *       @key - record key (u/d)
+       *       @data - data to be validated (i/u)
+       **/
+       function _validate($key=null, $data)
+       {
+               $mode = isset($data) ? (isset($key) ? 'u' : 'i') : 'd';
+
+               foreach($this->checks as $check) {
+
+                       if (strpos($check['mode'], $mode) !== false) {
+                               $msg = $check['msg'];
+                               $fld = $check['fld'];
+                               $opts = @$check['opts'];
+
+                               // precheck for existing 
+                               if ($mode == 'i' && $fld && !isset($data[$fld])) {
+                                       $msg = sprintf(_("Input parameter '%s' have to be set."), $check['fld']);
+                                       return $this->error($msg, $check['fld']);
+                               }
+
+                               switch($check['type']) {
+
+                                       case 'required':
+                                               if ($data[$fld]==='') {
+                                                       if (!$msg) $msg = sprintf(_("Parameter '%s' cannot be empty.", $check['fld']));
+                                                               return $this->error($msg, $check['fld']);
+                                               }
+                                               break;
+
+                                       case 'clean_file_name':
+                                               if (isset($data[$fld]) && ($data[$fld] != clean_file_name($data[$fld]))) {
+                                                       if (!$msg) $msg = sprintf(_("Parameter '%s' contains invalid characters.", $check['fld']));
+                                                       return $this->error($msg, $check['fld']);
+                                               }
+                                               break;
+
+                                       case 'range':
+                                               if (!$msg) $msg = sprintf(_("Parameter '%s' has invalid value.", $check['fld']));
+                                               // TODO: check at least one named parameter is passed
+                                               if (isset($opts['lt']) && !($data[$fld] < $opts['lt']) ||
+                                                       (isset($opts['gt']) && !($data[$fld] > $opts['gt'])) ||
+                                                       (isset($opts['min']) && !($data[$fld] < $opts['min'])) ||
+                                                       (isset($opts['max']) && !($data[$fld] > $opts['max'])) )
+                                                               return $this->error($msg, $check['fld']);
+
+//                                     case 'match':
+                                               break;
+
+                                       // user defined checks
+                                       default:
+                                               $func = $check['type'];
+                                               if (method_exists($this, $func)) {
+                                                       if (!$this->$func($data, $check['opts'], $key))
+                                                               return $this->error($msg, $check['fld']);
+                                               } else if (function_exists($func)) {
+                                                       if (!$func($data, $key, $check['opts'], $key))
+                                                               return $this->error($msg, $check['fld']);
+                                               }
+                               }
+                       }
+               }
+               return true;
+       }
+
+       /**
+       *
+       *       Returns editable status for selected record.
+       *       Array contains true for editable, false for readonly fields.
+       *       This looks redundant ('forbidden' update_check could be used)
+       *       but in fact the constraints are related to exact record, so changes with key.
+       **/
+       function edit_status($key)
+       {
+               $editables = array();
+
+               // default: all but key fields editable 
+               foreach ($this->fields as $fld=>$val)
+                       $editables[$fld] = !in_array($fld, (array)$this->key);
+
+               return $editables;
+       }
+
+
+       function delete_check($key)
+       {
+               return $this->_validate($key, null);
+       }
+
+       function insert_check($data)
+       {
+               return $this->_validate(null, $data);
+       }
+
+       function update_check($key, $data)
+       {
+               // Note: this does not allow change of key
+               return $this->_validate( $key, $data);
+       }
+
+       //===========================================================================
+       //      Database functions placeholders
+       
+       //
+       //      Generic read record routine
+       //
+       function get($key=null)
+       {
+               $defaults = array();
+               // return all defined default values
+               foreach ($this->fields as $name => $def)
+               {
+                       if(!is_numeric($name)) {
+                               if (is_string($def))
+                                       $defaults[$name] = $def;
+                               elseif (isset($def['dflt']))
+                                       $defaults[$name] = $def['dflt'];
+                       }
+               }
+               return $defaults;
+       }
+       //
+       //      Generic list record routine
+       //
+       abstract function get_all();
+       //
+       //      Generic update record routine
+       //
+       function update($key, $data)
+       {
+               if (!$this->update_check($key, $data))
+                       return false;
+
+               return true;
+       }
+       //
+       //      Generic delete record routine
+       //
+       function delete($key)
+       {
+               if (!$this->delete_check($key))
+                       return false;
+
+               return true;
+       }
+       //
+       //      Insert record
+       //
+       function insert($data)
+       {
+               if (!$this->insert_check($data))
+                       return false;
+
+               return true;
+       }
+
+}
+
+class data_set extends record_set {
+
+       function data_set($name, $fields, $key, $subset=null)
+       {
+               $this->record_set($name, $fields, $key, $subset);
+       }
+
+       //
+       //      Generic read record routine
+       //
+       function get($key=null)
+       {
+               if ($key===null)
+                       return parent::get();
+
+               $sql = "SELECT * FROM ".TB_PREF.$this->name." WHERE ";
+               $where = $this->subset ? (array)$this->subset : array();
+
+               if (is_array($this->key)) {
+                       foreach($this->key as $fld)
+                               if (isset($key[$fld]))
+                                       $where[$fld] = "`$fld`=".db_escape($key[$fld]);
+                               else
+                                       return $this->error(sprintf(_("Invalid key passed reading '%s'"), $this->name));
+               } else {
+                       $where = array($this->key => "`".$this->key."`=".db_escape($key));
+               }
+
+               $sql .= implode(' AND ', $where);
+               $result = db_query($sql);
+               if (!$result)
+                       return $this->error("Cannot get record from ".$this->name);
+
+               return $rec = db_num_rows($result) ? db_fetch_assoc($result) : null;
+       }
+       //
+       //      Generic list record routine
+       //
+       function get_all($where=null, $order_by=null)
+       {
+               $fields = array();
+               foreach($this->fields as $fld)
+                       $fields[] = '`'.$fld.'`';
+               $sql = "SELECT ".implode(',', $fields)." FROM ".TB_PREF.$this->name;
+
+               if ($where)
+                       $sql .= " WHERE ".($this->subset ? '('.$this->subset . ') AND ' : ''). $where;
+               if ($order_by) {
+                       $order_by = (array)$order_by;
+                       foreach($order_by as $i => $fld)
+                               $order_by[$i] = '`'.$fld.'`';
+                       $sql .= " ORDER BY ".implode(',', (array)$order_by);
+               }
+               $result = db_query($sql);
+               if ($result==false)
+                       return $this->error("Cannot get record from ".$this->name);
+
+               return $result;
+       }
+       //
+       //      Generic update record routine
+       //
+       function update($key, $data)
+       {
+               if (!parent::update($key, $data))       // validate data
+                       return false;
+
+               $sql = "UPDATE ".TB_PREF.$this->name." SET ";
+               $updates = array();
+
+               foreach($data as $fld => $value) {      // select only data relevant for this model
+                       if (in_array($fld, $this->fields))
+                               $updates[$fld] = "`$fld`=".db_escape($value);
+               }
+               if (count($updates) == 0)
+                       return $this->error(_("Empty update data for table ").$this->name);
+
+               $sql .= implode(',', $updates)." WHERE ";
+               $where = $this->subset ? (array)$this->subset : array();
+
+               if(is_array($this->key)) {                      // construct key phrase
+                       foreach($this->key as $fld)
+                               if (isset($key[$fld]))
+                                       $where[$fld] = "`$fld`=".db_escape($key[$fld]);
+                               else
+                                       return $this->error(sprintf(_("Invalid key for update '%s'"), $this->name));
+               } else {
+                       $where = array("`".$this->key."`=".db_escape($key));
+               }
+
+               $sql .= implode(' AND ', $where);
+               $result = db_query($sql);
+
+               if ($result===false)
+                       return $this->error("cannot update record in ".$this->name);
+
+               return $result;
+       }
+       //
+       //      Generic delete record routine
+       //
+       function delete($key)
+       {
+               if (!parent::delete_check($key))
+                       return false;
+
+               $sql = "DELETE FROM ".TB_PREF.$this->name;
+               $where = $this->subset ? (array)$this->subset : array();
+
+               if(is_array($this->key)) {
+                       foreach($this->key as $fld)
+                               if (isset($key[$fld]))
+                                       $where[$fld] = "`$fld`=".db_escape($key[$fld]);
+                               else
+                                       return $this->error(sprintf(_("Invalid key for update '%s'"), $this->name));
+               } else {
+                       $where = array("`".$this->key."`=".db_escape($key));
+               }
+
+               $sql .= " WHERE ".implode(' AND ', $where);
+               $result = db_query($sql);
+               if (!$result)
+                       return $this->error(_("Cannot update record in ").$this->name);
+
+               return $result;
+       }
+       //
+       //      Insert record
+       //
+       function insert($data)
+       {
+               if (!parent::insert_check($data))
+                       return false;
+
+               $sql = "INSERT INTO ".TB_PREF.$this->name. ' (';
+               $fields = array();
+               foreach($data as $fld => $value) {
+                       if (in_array($fld, $this->fields) || (is_array($this->key) ? in_array($this->key) : $fld==$this->key))
+                               $fields["`$fld`"] = db_escape($value);
+               }
+               if (!count($fields))
+                       return $this->error(_("Empty data set for insertion into ".$this->name));
+
+               $sql .= implode(',', array_keys($fields)) .') VALUES ('. implode(',', $fields).')';
+
+               $result = db_query($sql);
+               if (!$result)
+                       return $this->error(_("Cannot insert record into ").$this->name);
+
+               return $result;
+       }
+
+}
+
+/**
+*
+*      Data set as array of arrays/objects
+*
+*  TODO: default to: fields = ReflectionClass->getProperties
+**/
+class array_set extends record_set {
+
+       var $array = array();
+
+       var $object_class;      // name of record object class or null for arrays
+
+       function array_set($name, $fields, $key=null, &$arr=array(), $class = null)
+       {
+               $this->array = &$arr;
+               $this->object_class = $class;
+               $this->record_set($name, $fields, $key);
+       }
+
+       //===========================================================================
+       //      Database functions placeholders
+
+       //
+       //
+       //
+       function get($key=null)
+       {
+               if ($key===null)
+                       return parent::get();
+
+               return @$this->array[$key];
+       }
+       //
+       //      Generic list record routine
+       //
+       function get_all()
+       {
+               return $this->array;
+       }
+
+       function _set_record($data, $record = null)
+       {
+               if (!isset($record)) {
+                       if ($this->object_class) {
+                               $record = new $this->object_class;
+                       }
+                       else
+                               $record = array();
+               }
+               foreach(array_merge($this->fields, (array)$this->key) as $n => $fld)
+               {
+                       if (!is_numeric($n))
+                               $fld = $n;
+                       if (array_key_exists($fld, $data))
+                       {
+                               if ($this->object_class)
+                                       $record->$fld = $data[$fld];
+                               else
+                                       $record[$fld] = $data[$fld];
+                               $updates = true;
+                       }
+               }
+               return $updates ? $record : null;
+       }
+       //
+       //      Generic update record routine
+       //
+       function update($key, $data)
+       {
+               if (parent::update($key, $data) === false)
+                       return false;
+
+               $record = $this->_set_record($data, $this->array[$key]);
+               if (!$record)
+                       return $this->error(_("Empty update data for array ").$this->name);
+
+               $this->array[$key] = $record;
+
+               return true;
+       }
+       //
+       //      Delete record
+       //
+       function delete($key)
+       {
+               if (!parent::delete($key))
+                       return false;
+
+               unset($this->array[$key]);
+
+               return true;
+       }
+       //
+       //      Insert record
+       //
+       function insert($data)
+       {
+               if (parent::insert($data) === false)
+                       return false;
+
+               $record = $this->_set_record($data);
+               if (!$record)
+                       return $this->error(_("Empty data for array ").$this->name);
+
+               $this->array[] = $record;
+
+               $ret = array_keys($this->array);
+               return end($ret);
+       }
+}
+
diff --git a/includes/db/class.reflines_db.inc b/includes/db/class.reflines_db.inc
new file mode 100644 (file)
index 0000000..344a18b
--- /dev/null
@@ -0,0 +1,179 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+include_once 'class.data_set.inc';
+
+/**
+*      Reference lines.
+*
+**/
+
+class reflines_db extends data_set {
+       function reflines_db()
+       {
+               $this->set_validator('prefix:ui:_check_prefix', _("This prefix conflicts with another one already defined. Prefix have to be unambigous."));
+               $this->set_validator('prefix:ui:_check_template', _("Invalid template format."));
+               $this->set_validator('trans_type:ui:required', _("Transaction type cannot be empty."));
+               $this->set_validator('pattern:ui:required', _("Next reference cannot be empty."));
+               $this->data_set('reflines', 
+                       array('trans_type', 'prefix', 'description', 'default', 'pattern', 'id', 'inactive'), 
+                       'id');
+       }
+
+       /*
+               Prefix cannot be ambigous.
+       */
+       function _check_prefix($data, $dummy_opt, $key)
+       {
+               $cond = "`id`<>".db_escape($key)." AND `trans_type`=".db_escape($data['trans_type']);
+               if ($data['prefix'] === '')
+                       $cond .= " AND `prefix`='".$data['prefix']."'";
+               else
+                       $cond .= "AND ((LOCATE('".$data['prefix']."', CONCAT(`prefix`,`pattern`))=1 OR (`prefix`<>'' AND LOCATE(`prefix`, '".$data['prefix'].$data['pattern']."')=1)))";
+
+               return db_num_rows($this->get_all($cond)) == 0;
+       }
+
+       function _check_template($data, $dummy_opt, $key)
+       {
+               global $refline_options, $refline_placeholders;
+
+               if (strpbrk($data['prefix'], '{}') !== false)
+                       return $this->error(_("You cannot use placeholders in refline prefix."));
+
+               if (substr_count($data['pattern'], '{') != substr_count($data['pattern'], '}'))
+                       return $this->error(_("Curly brackets does not balance."));
+
+               if (preg_match_all('/\{([^\}]*)\}/', $data['pattern'], $match)) // placeholders defind in template
+               {
+                       $numph = 0;
+                       foreach($match[1] as $ph) {
+                               if (is_numeric($ph))
+                                       $numph++;
+                               elseif (!isset($refline_placeholders[$ph]) || !@in_array($refline_placeholders[$ph], $refline_options[$data['trans_type']])) {
+                                       $allowed = array();
+                                       foreach($refline_placeholders as $id => $dt)
+                                                if (in_array($dt, $refline_options[$data['trans_type']]))
+                                                       $allowed[] = $id;
+
+                                       return $this->error(sprintf(_("Invalid placeholder '%s'. Placeholders allowed for this transaction type are: %s."),
+                                               $ph, implode(',', $allowed)));
+                               }
+                       }
+
+                       if ($numph !== 1)
+                               return $this->error(_("Missing numeric placeholder. If you want to use template based references, you have to define numeric placeholder too."));
+               }
+               return true;
+       }
+
+       function is_used($prefix, $trans_type)
+       {
+
+               $sql = "SELECT *
+                       FROM (SELECT r.* FROM 0_refs r 
+                               LEFT JOIN ".TB_PREF."voided as v
+                                       ON r.id=v.id AND r.type=v.type
+                               WHERE r.type=".db_escape($trans_type)." AND ISNULL(v.id)
+                               ) ref
+                       LEFT JOIN 0_reflines line ON ref.type=line.trans_type AND substr(ref.reference,1, LENGTH(line.prefix))= line.prefix AND line.prefix<>''
+                       WHERE ".($prefix == '' ? "ISNULL(prefix)" : "prefix=".db_escape($prefix));
+
+               $res = db_query($sql, "cannot check reference line");
+
+               return db_num_rows($res);
+       }
+
+       function delete_check($ref_id)
+       {
+               $rec = $this->get($ref_id);
+               if ($rec['default'])
+                       return $this->error(_("Reference line which is default for any transaction type cannot be deleted."));
+
+               if ($this->is_used($rec['prefix'], $rec['trans_type']))
+                       return $this->error(_("Reference line cannot be deleted because it is already in use."));
+
+               return true;
+       }
+
+       function _set_as_default($id, $type)
+       {
+               $sql  = "UPDATE ".TB_PREF."reflines SET `default`=(`id`=".db_escape($id).")
+                        WHERE `trans_type`=".db_escape($type);
+               return db_query($sql, "cannot update default refline");
+       }
+
+       function insert($data)
+       {
+               if (!parent::insert($data))
+                       return false;
+               if (@$data['default'])
+                       return $this->_set_as_default(db_insert_id(), $data['trans_type']);
+               return true;
+       }
+
+       function update($key, $data)
+       {
+               if (!parent::update($key, $data))
+                       return false;
+               if (@$data['default'])
+                       return $this->_set_as_default($key , $data['trans_type']);
+               return true;
+       }
+
+       function get_default($type)
+       {
+               $sql = "SELECT * FROM ".TB_PREF."reflines WHERE trans_type=".db_escape($type)." AND `default`";
+               $result = db_query($sql, "cannot retreive default refline for trnasaction type $type");
+               return db_fetch($result);
+       }
+
+       function count($type, $all=false)
+       {
+               $sql = "SELECT count(*) FROM ".TB_PREF."reflines WHERE trans_type=".db_escape($type);
+               if (!$all)
+                       $sql .= " AND !inactive";
+               $result = db_query($sql, "cannot retreive refline count for transaction type $type");
+               $rec = db_fetch($result);
+               return $rec ? $rec[0] : 0;
+       }
+
+       /*
+               Recognize refline by reference prefix
+       */
+       function find_refline_id($reference, $type, $fallback = true)
+       {
+               $sql = "SELECT * FROM ".TB_PREF."reflines WHERE trans_type=".db_escape($type)
+                       ." AND CHAR_LENGTH(`prefix`) AND LEFT('$reference', CHAR_LENGTH(`prefix`)) = `prefix`";
+               if ($fallback)  // if not found return refline with empty prefix
+                       $sql .= " UNION SELECT * FROM ".TB_PREF."reflines WHERE trans_type=".db_escape($type)." AND `prefix`=''";
+               $ret = db_query($sql, "cannot check reference line id");
+               $line = db_fetch($ret);
+
+               if (!$fallback && (db_num_rows($fallback) != 1))        // more than one record means ambigous reference line
+                       return null;
+
+               return $line ? $line['id'] : null;
+       }
+
+       function save_next($type, $reference, $line=null)
+       {
+           $sql = "UPDATE ".TB_PREF."reflines SET pattern=SUBSTRING(" . db_escape(trim($reference)) .", LENGTH(`prefix`)+1)"
+               . " WHERE trans_type = ".db_escape($type) . " AND ";
+
+               if (isset($line))
+                       $sql .= "`id`=".db_escape($line);
+               else
+                       $sql .= "`default`";
+
+               return db_query($sql, "The next transaction ref for $type could not be updated");
+       }
+}
index 9c9d2b2e3e68756b225184a06d9f74950c42bf5f..87f045f8cdd6bcecea0c776d18204b11e3456583 100644 (file)
@@ -320,7 +320,7 @@ function handle_negative_inventory($stock_id, $quantity, $standard_cost, $date_)
                global $Refs;
 
                $id = get_next_trans_no(ST_JOURNAL);
-               $ref = $Refs->get_next(ST_JOURNAL);
+               $ref = $Refs->get_next(ST_JOURNAL, null, $date_);
                $diff = round($qoh*get_standard_cost($stock_id) + $quantity*$standard_cost, user_price_dec());
 
                if ($diff != 0)
diff --git a/includes/db/references_db.inc b/includes/db/references_db.inc
deleted file mode 100644 (file)
index 4933d8d..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-/**********************************************************************
-    Copyright (C) FrontAccounting, LLC.
-       Released under the terms of the GNU General Public License, GPL, 
-       as published by the Free Software Foundation, either version 3 
-       of the License, or (at your option) any later version.
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
-    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
-***********************************************************************/
-//--------------------------------------------------------------------------------------------------
-
-function get_reference($type, $id)
-{
-       $sql = "SELECT * FROM ".TB_PREF."refs WHERE type=".db_escape($type)." AND id=".db_escape($id);
-
-       $result = db_query($sql, "could not query reference table");
-    $row = db_fetch($result);
-    return $row['reference'];
-}
-
-//--------------------------------------------------------------------------------------------------
-function update_reference($type, $id, $reference)
-{
-    $sql = "REPLACE ".TB_PREF."refs SET reference=".db_escape($reference)
-                       .", type=".db_escape($type).", id=".db_escape($id);
-    db_query($sql, "could not update reference entry");
-}
-
-//--------------------------------------------------------------------------------------------------
-
-function delete_reference($type, $id)
-{
-       $sql = "DELETE FROM ".TB_PREF."refs WHERE type=".db_escape($type)." AND id=".db_escape($id);
-
-       return db_query($sql, "could not delete from reference table");
-}
-
-//--------------------------------------------------------------------------------------------------
-
-function find_reference($type, $reference)
-{
-       // ignore refs references for voided transactions
-       $sql = "SELECT r.id FROM ".TB_PREF."refs r LEFT JOIN ".TB_PREF."voided v ON"
-               ." r.type=v.type AND r.id=v.id"
-               ." WHERE r.type=".db_escape($type)
-               ." AND reference=".db_escape($reference)
-               ." AND ISNULL(`memo_`)";
-
-       $result = db_query($sql, "could not query reference table");
-
-    return (db_num_rows($result) > 0);
-}
-
-//--------------------------------------------------------------------------------------------------
-
-function save_next_reference($type, $reference)
-{
-    $sql = "UPDATE ".TB_PREF."sys_types SET next_reference=" . db_escape(trim($reference)) 
-               . " WHERE type_id = ".db_escape($type);
-
-       db_query($sql, "The next transaction ref for $type could not be updated");
-}
-
-//--------------------------------------------------------------------------------------------------
-
-function get_next_reference($type)
-{
-    $sql = "SELECT next_reference FROM ".TB_PREF."sys_types WHERE type_id = ".db_escape($type);
-
-    $result = db_query($sql,"The last transaction ref for $type could not be retreived");
-
-    $row = db_fetch_row($result);
-    return $row[0];
-}
-
-//----------------------------------------------------------------------------
-//
-//     Check if reference was not used so far (for other transaction than $trans_no)
-//
-function is_new_reference($ref, $type, $trans_no=0)
-{
-       $db_info = get_systype_db_info($type);
-       $db_name = $db_info[0];
-       $db_type = $db_info[1];
-       $db_trans = $db_info[2];
-       $db_ref = $db_info[3];
-       
-       $ref = db_escape(trim($ref));
-       $type = db_escape($type);
-       
-       if ($db_ref == null) { // journal or bank trans store references in refs table
-               $db_name = TB_PREF."refs";
-               $db_type = 'type';
-               $db_trans = 'id';
-               $db_ref = 'reference';
-       }
-
-       if ($db_type != null) {
-               $sql = "SELECT $db_ref FROM $db_name tbl
-                       LEFT JOIN ".TB_PREF."voided v ON 
-                               tbl.$db_type=v.type AND tbl.$db_trans=v.id
-                       WHERE $db_ref=$ref AND ISNULL(v.id)
-                               AND tbl.$db_type=$type";
-       } else {
-               $sql = "SELECT $db_ref ref FROM $db_name tbl
-                       LEFT JOIN ".TB_PREF."voided v ON 
-                               v.type=$type AND tbl.$db_trans=v.id
-                       WHERE $db_ref=$ref AND ISNULL(v.id)";
-       }
-       if ($trans_no)
-                       $sql .= " AND tbl.`$db_trans` != ".db_escape($trans_no);
-
-       $result = db_query($sql, "could not test for unique reference");
-
-       return (db_num_rows($result) == 0);
-
-}
-
-
index bba6f155545d3c8ce773d3b8c35abb930d93b732..a5e872d703e0dcee08afefff37dae24e039c29c0 100644 (file)
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
 ***********************************************************************/
-include_once($path_to_root . "/includes/db/references_db.inc");
+include_once($path_to_root . "/includes/db/class.reflines_db.inc");
 //---------------------------------------------------------------------------------------------
+// 2.4 - further changes toward removing refs table introduced:
+//     . all transactions now have references stored in trans table.
+//  . all reference related moved to class (is_new_reference yet preserved)
+//     . template based reflines implemented
 //
-// For now (2.3) the references system has somewhat inconsistent design scheme.
-// Most transactions store references in respective table, but this is not the case
-// for journal entries. All references regardless of type are stored also in refs table. 
-// Reference uniquness now can be checked with is_new_reference() for all transactions. 
-// In near future this should be fixed either with removing reference fields 
-// in transaction tables, or adding ref in bank transaction/journal and removing refs table.
-//
+// FIXME:
+//             - implement refline field in all transaction tables (obsoletes not always accurate find_refline_id)
+//             - remove save() and restore_last() - for now preserved for reflines without placeholder
+//             - see fixmes below
+//             - remove refs table and create view instead (need e.g. CREATE VIEW support in db_import/db_export)
+
+$refline_options = array(
+       ST_JOURNAL => array('date', 'user'),
+       ST_COSTUPDATE => array('date', 'user'),
+
+       ST_BANKPAYMENT => array('date', 'user'),
+       ST_BANKDEPOSIT => array('date', 'user'),
+       ST_BANKTRANSFER => array('date', 'user'),
+       ST_SUPPAYMENT => array('date', 'user'),
+       ST_CUSTPAYMENT => array('date', 'user'),
+
+       ST_SALESORDER => array('date', 'customer', 'branch', 'user', 'pos'),
+       ST_SALESQUOTE => array('date', 'customer', 'branch', 'user', 'pos'),
+       ST_SALESINVOICE => array('date', 'customer', 'branch', 'user', 'pos'),
+       ST_CUSTCREDIT => array('date', 'customer', 'branch', 'user', 'pos'),
+       ST_CUSTDELIVERY => array('date', 'customer', 'branch', 'user', 'pos'),
+
+       ST_LOCTRANSFER => array('date', 'location', 'user'),
+       ST_INVADJUST => array('date', 'location', 'user'),
+
+       ST_PURCHORDER => array('date', 'location', 'supplier', 'user'),
+       ST_SUPPINVOICE => array('date', 'location', 'supplier', 'user'),
+       ST_SUPPCREDIT => array('date', 'location', 'supplier', 'user'),
+       ST_SUPPRECEIVE => array('date', 'location', 'supplier', 'user'),
+
+       ST_WORKORDER => array('date', 'location', 'user'),
+       ST_MANUISSUE => array('date', 'location', 'user'),
+       ST_MANURECEIVE => array('date', 'user'),
+);
+
+$refline_placeholders = array(
+       'MM' => 'date',
+       'YY' => 'date',
+       'YYYY' => 'date',
+       'UU' => 'user',
+       'P' => 'pos',
+//      FIXME:  for placeholders below all the code should work, but as the ref length is variable,
+//        length specification in placeholder format should be implemented.
+//     'C' => 'customer',
+//     'B' => 'branch',
+//     'S' => 'supplier',
+//     'L' => 'location'
+);
 
 class references 
 {
-       //
-       //      Get reference from refs table for given transaction.
-       //      Used for transactions which do not hold references (journal and bank).
-       //
-       function get($type, $id) 
+       var $reflines;
+       
+       function references()
        {
-               return get_reference($type, $id);
+               $this->reflines = new reflines_db();
        }
+
+       function _legacy_line($refline)
+       {
+               return strpbrk($refline['pattern'], '{}') == false;
+       }
+
+       function _parse_next($type, $template, $context=null)
+       {
+               global $refline_options, $refline_placeholders;
+
+               // date based placeholders are always allowed, so default for non-array context is date
+               if (!isset($context))
+                       $context = new_doc_date();
+
+               if (is_string($context))
+                       $context = array('date' => $context);
+
+               $context['user'] = $_SESSION['wa_current_user']->user;
+               $context['pos'] = $_SESSION['wa_current_user']->pos;
+               $out = '';
+
+               while(($start = strpos($template, '{')) !==false) {
+
+                       $out .= substr($template, 0, $start);
+                       $stop = strpos($template, '}');
+                       if ($stop === false) {
+                               display_warning(_("Invalid refline template."));
+                               $out .= $template; // debug
+                               break;
+                       }
+                       $ph = substr($template, $start+1, $stop-$start-1);
+                       $template = substr($template, $stop+1);
+
+                       if (isset($refline_placeholders[$ph])) {
+                               if (!isset($context[$refline_placeholders[$ph]]))
+                               {
+                                       display_warning(sprintf(_("Missing refline context data: '%s'"), $refline_placeholders[$ph]));
+                                       $out .= $ph; // debug
+                               } else {
+                                       switch ($ph)
+                                       {
+                                               case 'MM':
+                                               case 'YY':
+                                               case 'YYYY':
+                                                       list($day, $month, $year) = explode_date_to_dmy($context['date']);
+                                                       $out .= $ph == 'MM' ? sprintf('%02d', $month) : ($ph == 'YY' ? sprintf('%02d', $year%100): sprintf('%04d', $year));
+                                                       break;
+                                               case 'C':
+                                                       $out .= sprintf('%d', $context['customer']);
+                                                       break;
+
+                                               case 'B':
+                                                       $out .= sprintf('%d', $context['branch']);
+                                                       break;
+
+                                               case 'S':
+                                                       $out .= sprintf('%d', $context['supplier']);
+                                                       break;
+
+                                               case 'L':
+                                                       $out .= sprintf('%s', $context['location']);
+                                                       break;
+
+                                               case 'P':
+                                                       $out .= sprintf('%s', $context['pos']);
+                                                       break;
+
+                                               case 'UU':
+                                                       $out .= sprintf('%02d', $context['user']);
+                                               break;
+                                       }
+                               }
+                       } elseif (is_numeric($ph)) {
+                               $out .= '{'.$ph.'}'; // index placeholder
+                       }
+               }
+
+               if (!preg_match('/^([^\{]*)?\{([^\}]*)\}(.*)/', $out, $match)) {        // parse index
+                       display_error(_("Missing numeric placeholder in refline definition."));
+                       return $out;
+               }
+
+               $prefix = $match[1];
+               $postfix = $match[3];
+
+               $db_info = get_systype_db_info($type);
+               $trans_table = $db_info[0];
+               $type_fld = $db_info[1];
+               $tno_fld = $db_info[2];
+               $ref_fld = $db_info[3];
+
+               // retrieve last ref number in the refline from original transaction table
+               $sql = "SELECT MAX(CAST(SUBSTR($ref_fld, ".(strlen($prefix)+1).",LENGTH($ref_fld)-".(strlen($postfix)+strlen($prefix)).") AS UNSIGNED))"
+                               ." FROM `$trans_table` tbl
+                                       LEFT JOIN ".TB_PREF."voided v ON tbl.`$tno_fld`=v.id AND v.type=$type"
+                               ." WHERE ISNULL(v.id)"
+                               .($type_fld ? " AND tbl.`$type_fld`=$type" : '')
+                               ." AND `$ref_fld` REGEXP ".db_escape('^'.preg_quote($prefix).'[0-9]*'.preg_quote($postfix).'$');
+               $result = db_query($sql, 'cannot retrieve last reference');
+               $result = db_fetch_row($result);
+
+                       // fill with zeros to the length of original index placeholder
+               return $prefix.sprintf('%0'.strlen($match[2]).'d', $result[0]+1).$postfix;
+       }
+
        //
-       // Check if reference is used for any non voided transaction (used for ST_JOURNALENTRY type)
+       //      Get/check transaction reference.
+       //      $ref!=null => check reference is not used (or unique for $trans_no!=0)
+       //  $trans!=0 $ref=null => retrieve reference for the $type/$trans_no (if any)
        //
-       function exists($type, $reference) 
+       function _get($type, $trans_no=0, $ref=null)
+       {
+               $db_info = get_systype_db_info($type);
+               $trans_table = $db_info[0];
+               $type_fld = $db_info[1];
+               $tno_fld = $db_info[2];
+               $ref_fld = $db_info[3];
+
+               $type = db_escape($type);
+
+               $sql = "SELECT `$ref_fld` 
+                               FROM `$trans_table` tbl
+                                       LEFT JOIN ".TB_PREF."voided v ON 
+                               tbl.`$tno_fld`=v.id AND v.type=$type"
+                       ." WHERE ISNULL(v.id)"
+                       .($type_fld ? " AND tbl.`$type_fld`=$type" : '');
+               if ($ref)
+               {
+                       $sql .= " AND tbl.`$ref_fld`=".db_escape(trim($ref));
+                       if ($trans_no)
+                               $sql .= " AND tbl.`$tno_fld` != ".db_escape($trans_no);
+               } else {
+                       $sql .= " AND tbl.`$tno_fld`=".db_escape($trans_no);
+               }
+
+               $result = db_query($sql, "could not test for unique reference");
+               if (!$result)
+                       return false;
+
+               $result = db_fetch_row($result);
+               return $result[0];
+       }
+
+       function is_new_reference($ref, $type, $trans_no=0)
        {
-               return (find_reference($type, $reference) != null);
+               return !$this->_get($type, $trans_no, $ref);
        }
+
        //
-       // Get default reference on new transaction creation.
+       // Get default reference for new transaction.
        //
-       function get_next($type) 
+       function get_next($type, $line=null, $context=null
        {
-               return get_next_reference($type);
+
+               if (isset($line))
+                       $refline = $this->reflines->get($line);
+               else {
+                       $refs = $this->reflines->get_all("trans_type=".db_escape($type)." AND `default`");
+                       $refline = db_fetch($refs);
+               }
+
+               if ($this->_legacy_line($refline))
+                       return $refline['pattern'];
+
+               return $this->_parse_next($type, $refline['prefix'].$refline['pattern'], $context);
        }
+
+       /**
+       *       Normalize reference to format allowed by refline (optionally selected by prefix).
+       *       FIXME: currently this is fake function which return either input reference or 
+       *       next reference when no line has been recognized.
+       **/
+       function normalize($ref, $type, $context, $line=null)
+       {
+               if (!isset($type)) // inquiries
+                       return $ref;
+
+               if (!$line)
+                       $line = $this->reflines->find_refline_id($ref, $type);
+
+               return $this->is_valid($ref, $type, $context, $line) ? $ref : $this->get_next($type, $line, $context);
+       }
+
        //
        // Check reference is valid before add/update transaction.
+       // FIXME: does not check leading zeros in number
        //
-       function is_valid($reference
+       function is_valid($reference, $type, $context=null, $line=null)
        {
-               return strlen(trim($reference)) > 0;
+               if (!isset($line))
+                       $line = $this->reflines->find_refline_id($reference, $type, true);
+
+               if (!isset($line))
+                       return false;
+
+               $refline = $this->reflines->get($line);
+
+               if ($this->_legacy_line($refline))      //legacy non-templated line
+                       return strlen(trim($reference)) > 0;
+
+               $regex = preg_quote($refline['prefix'].$refline['pattern']);
+               if (!is_array($context))
+                       $context = array('date'=>$context);
+
+               $context['pos'] = $_SESSION["wa_current_user"]->pos;
+
+               if (is_date(@$context['date']))
+               {
+                       list($year4, $month, $day) = explode("-", date2sql($context['date']));
+                       $year2 = substr($year4, 2);
+               } else
+               {
+                       $month = '\d{2,}';
+                       $year2 = '\d{2,}';
+                       $year4 = '\d{4,}';
+               }
+               $cust = @$context['customer'] ? $context['customer'] : '\d+';
+               $supp = @$context['supplier'] ? $context['supplier'] : '\d+';
+               $branch = @$context['branch'] ? $context['branch'] : '\d+';
+               $location = @$context['location'] ? $context['location'] : '[a-z0-9]+';
+               $pos = @$context['pos'] ? $context['pos'] : '\d+';
+               $user = sprintf("%02d", $_SESSION['wa_current_user']->user);
+
+               $regex = preg_replace(
+                       array(
+                               '/\\\{/',       // unquote placeholders
+                               '/\\\}/',
+                               '/\{MM\}/',
+                               '/\{YY\}/',
+                               '/\{YYYY\}/',
+                               '/\{C\}/',
+                               '/\{B\}/',
+                               '/\{S\}/',
+                               '/\{L\}/',
+                               '/\{UU\}/',
+                               '/\{P\}/',
+                               '/\{\d+}/',
+                       ),
+                       array(
+                               '{',
+                               '}',
+                               $month,
+                               $year2,
+                               $year4,
+                               $cust,
+                               $branch,
+                               $supp,
+                               $location,
+                               $user,
+                               $pos,
+                               '\d+',
+                       ), $regex);
+
+               $regex = '"^'.$regex.'"i';
+
+               return preg_match($regex, $reference, $match) ? 1 : 0;
        }
+
        //
        //      Save reference (and prepare next) on write transaction.
        //
-       function save($type, $id, $reference) 
+       function save($type, $id, $reference, $line = null
        {
-               update_reference($type, $id, $reference); // store in refs table
-               if ($reference == $this->get_next($type)) { // if reference was bigger or not changed from default
+               if ($reference == 'auto')
+                       return;
+
+           $sql = "REPLACE ".TB_PREF."refs SET reference=".db_escape($reference)
+                       .", type=".db_escape($type).", id=".db_escape($id);
+       db_query($sql, "could not update reference entry");
+
+               if (!isset($line))
+               {
+                       $line = $this->reflines->find_refline_id($reference, $type);
+               }
+
+               $refline = $this->reflines->get($line);
+                // legacy code used with simple templates
+               if ($this->_legacy_line($refline) && ($reference == $this->get_next($type, $line))) { // if reference was not changed from default
                        $next = $this->_increment($reference);  // increment default
-                       save_next_reference($type, $next);
+                       $this->reflines->save_next($type, $next, $line);
                }
        }
        //
        // Restore previous reference (if possible) after voiding transaction.
        //
-       function restore_last($type, $id) 
+       function restore_last($type, $id)
        {
+               // get refline for removed document reference
                $reference = get_reference($type, $id);
-               $prev = $this->_increment($this->get_next($type), true); //decrement
-               if ($reference==$prev) {
-                       save_next_reference($type, $prev);
+               $line = $this->reflines->find_refline_id($reference, $type);
+               $refline = $this->reflines->get($line);
+
+               if ($this->_legacy_line($refline)) // legacy code used with simple templates
+               {
+                       $last = $this->_increment($this->get_next($type, $line), true); // find last reference used in this line
+                       if ($reference == $last)
+                       {
+                               // save last reference as next
+                           $sql = "UPDATE ".TB_PREF."reflines SET pattern=SUBSTRING(" . db_escape(trim($last)) .", LENGTH(`prefix`)+1)"
+                                       . " WHERE trans_type = ".db_escape($type) . " AND `id`=".db_escape($line);
+
+                               db_query($sql, "The next transaction ref for $type could not be updated");
+                       }
                }
        }
+
        //-----------------------------------------------------------------------
        //
        //      Increments (or decrements if $back==true) reference template
        //
        function _increment($reference, $back=false) 
        {
-               // New method done by Pete. So f.i. WA036 will increment to WA037 and so on.
+               // Legacy code used when no palceholder is in use:
+               //  WA036 will increment to WA037 and so on.
                // If $reference contains at least one group of digits,
         // extract first didgits group and add 1, then put all together.
         // NB. preg_match returns 1 if the regex matches completely 
@@ -98,5 +405,23 @@ class references
         else 
             return $reference;
        }
+
+}
+
+//----------------------------------------------------------------------------
+//
+//     Check if reference was not used so far (for other transaction than $trans_no)
+//
+function is_new_reference($ref, $type, $trans_no=0)
+{
+       global $Refs;
+
+       return $Refs->is_new_reference($ref, $type, $trans_no);
 }
 
+function get_reference($type, $trans_no)
+{
+       global $Refs;
+
+       return $Refs->_get($type, $trans_no);
+}
diff --git a/includes/ui/class.crud_view.inc b/includes/ui/class.crud_view.inc
new file mode 100644 (file)
index 0000000..8572fdb
--- /dev/null
@@ -0,0 +1,756 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+
+include_once $path_to_root.'/includes/db/class.data_set.inc';
+
+class UI {
+       var $ui_mode;
+
+       // formatters
+       function text($value, $name='', $opts=array())
+       {
+               $text = array('label', 'size'=>"", 'max'=>"", 'title'=>false,   'labparams'=>"", 'post_label'=>"", 'inparams'=>"");
+               $opts = array_merge($text, $opts);
+
+               if (!$name)
+                       return $value;
+
+               call_user_func_array('text_cells', $opts);
+       }
+}
+/*
+       TODO: for php5:
+       . use __construct in base class to avoid need for implicit call to parent constructor.
+       . use private instead _* function name convention
+*/
+//
+//     User input-output conversions.
+//
+class user_view {
+
+       var     $data;          // data in php format
+       var $fields;    // input fields format descriptions
+       var $errors = array();
+       var $dec;
+       var $name;
+
+       function user_view($name)
+       {
+               $this->name = $name;
+       }
+
+       function error($msg, $context=null)
+       {
+               // save error message
+               if (!isset($context))
+                       $context = count($this->errors);
+               $this->errors[$context] = $msg;
+
+               return false;
+       }
+       /*
+               Input/output formatters - convert values between php/user domains.
+       */
+       function _format_input($value, $fmt)
+       {
+               switch($fmt) {
+                       case 'stock':
+                               $this->dec = get_qty_dec($value);
+                               return $value;
+                       case 'price':
+                       case 'qty':
+                       case 'number':
+                                   return user_numeric($value);
+                       case 'percent':
+                                       return user_numeric($value)/100;
+                       case 'text':
+                       case 'date':
+                       default:
+                               return $value;
+               }
+       }
+       //
+       // Returns formatted value
+       //
+       function _format_output($value, $fmt)
+       {
+               switch($fmt) {
+                       case 'price':
+                               return price_format($value);
+                       case 'qty':
+                               return number_format2($value, $this->dec);
+                       case 'number':
+                               return number_format2($value);
+                       case 'percent':
+                               return percent_format($value*100);
+                       case 'stock':
+                               $this->dec = get_qty_dec($value); // retrieve dec for use in following qty fields
+                       case 'text':
+                       case 'date':
+                       default:
+                               return $value;
+               }
+       }
+       /**
+       *       Returns html element for given field
+       *       @mode - true for edit, false for read-only
+       **/
+       function _format_cells($value, $fmt, $mode)
+       {
+               $value = $this->_format_output($fmt);
+
+               // available formatters with parameters
+               $formatters = array(
+                       'email_cell' => array('label', 'params'=>'', 'id'=>null),
+                       'amount_cell' => array('label'=>null, 'bold'=>false, 'params'=>'', 'id'=>null),
+                       'text_cells' => array('label', 'name', 'value'=>null, 'size'=>"", 'max'=>"", 'title'=>false,
+                               'labparams'=>"", 'post_label'=>"", 'inparams'=>"")
+               );
+               // format functions used in various modes
+               $formats = array(
+                       // field format => (view [,edit])
+                       '' => array('label_cell', 'text_cells'), // default
+                       'price' => array('label_cell', 'amount_cell'),
+                       'qty',
+                       'number',
+                       'percent',
+                       'stock',
+                       'text',
+                       'date',
+               );
+       }
+
+       /**
+       *
+       *       PHP->user format values convertion.
+       *
+       **/
+       function set_output($data=null, &$output=null)
+       {
+               if (isset($data))
+                       $this->data = $data;
+
+               if (!isset($output)) {
+                       $output = &$_POST;
+                       $prefix = $this->name;
+               } else
+                       $prefix = '';
+
+               foreach($this->fields as $name => $fmt) {
+
+                       if (is_int($name)) {
+                               $name = $fmt;
+                               $fmt = array();
+                       } elseif (!is_array($fmt))
+                               $fmt = array('fmt' => $fmt);
+
+                       $post = $prefix.(isset($fmt['post']) ? $fmt['post'] : $name);
+
+                       $fld = isset($fmt['fld']) ? $fmt['fld'] : $name;
+
+                       if (is_object($this->data))
+                               $value = isset($this->data->$fld) ?     $this->data->$fld : @$fmt['dflt'];
+                       else
+                               $value = isset($this->data[$fld]) ?     $this->data[$fld] : @$fmt['dflt'];
+                       if(isset($value))
+                               $output[$post] = $this->_format_output($value, @$fmt['fmt']);
+               }
+       }
+
+       /**
+       *
+       *       User->php format values convertion.
+       *       $input - data in user format
+       *       $all - return also null values for non-existing input field.
+       **/
+       function get_input($input=null, $all=false)
+       {
+               if (!isset($input))
+                       $input = $_POST;
+
+               if ($this->name)        // strip view name prefix
+                   foreach($input as $postkey=>$postval )
+               {
+                               if (strpos($postkey, $this->name) === 0)
+                               {
+                                       $id = substr($postkey, strlen($this->name));
+                                       $input[$id] = $postval;
+                               }
+                               unset($input[$postkey]);
+               }
+
+       $data = array();
+               foreach ($this->fields as $name => $fmt) {
+                       if (is_int($name)) {    // direct string passed: this is name of field
+                               $name = $fmt;
+                               $fmt = array(); // default format
+                       } elseif (!is_array($fmt))
+                               $fmt = array('fmt' => $fmt);
+                       $post = isset($fmt['post']) ? $fmt['post'] : $name; // input name (default to field name)
+                       $fld = isset($fmt['fld']) ? $fmt['fld'] : $name;        // input value (default to field name)
+
+//                     if ($all || array_key_exists($post, $input))
+//                     {
+                               $value = $this->_format_input(@$input[$post], @$fmt['fmt']);
+
+//                             if (is_array($data))
+                               if ($all || isset($value))
+                                       $data[$fld] = $value;
+//                             else
+//                                     $data->$fld = $value;
+//                     }
+               }
+
+               return $data;
+       }
+
+       //--------------------------------------------------------
+       //
+       //      Return data formatted according to field descriptions.
+       //
+       function get_fields_views($input=null, $mode=null)
+       {
+
+               if (!isset($input))
+                       $input = $_POST;
+
+               $view = array();
+               foreach ($this->fields as $name => $fmt) {
+                       if (is_int($name)) {
+                               $name = $fmt;
+                               $fmt = array();
+                       }
+                       $post = isset($fmt['post']) ? $fmt['post'] : $name;
+                       $fld = isset($fmt['fld']) ? $fmt['fld'] : $name;
+
+                       $value = $this->_format_cells(@$input[$post], @$fmt['fmt'], $mode);
+
+                       $view[$fld] = $value;
+               }
+               return $view;
+       }
+
+}
+
+//
+//     Template for simple table editors
+//
+
+class simple_crud_view extends user_view {
+       var $name;
+               // object status:
+       var $Mode = 'RESET';
+       var $selected_id;
+       var $prev_id;
+
+       var $_none = ''; // selector value when no item is selected
+       var $pre_handlers; // control buttons and related methods called before view display
+       var $views;
+       var $data = array();
+       var $fields;
+       var $tool_buttons;
+       var $options = array(
+               'delete' => true,               // true or message for successfull action.
+               'update' => true,
+               'insert' => true,
+               'clone' => true,
+       );
+       var $dec;
+       var $data_set;
+       var $display_both = false; //when set to true both list and editor are displayed all the time (eventually set in sub classes)
+       //
+       //
+       function simple_crud_view($name, $data_set = null, $options=array())
+       {
+               $this->user_view($name);
+
+               $this->options = array_merge($this->options, $options);
+
+               $this->views[''] = 'list_view';                 // default view
+
+               if ($this->options['update'])
+                       $this->_add_action('Edit', '_edit', _('Edit'), _('Edit document line'), ICON_EDIT, '',
+                               'editor_view');
+
+               if ($this->options['delete'])
+                       $this->_add_action('Delete', '_delete', _('Delete'), _('Remove line from document'), ICON_DELETE, '',
+                               'list_view');
+
+               if ($this->options['update'])
+                       $this->_add_action('UPDATE', '_update', _('Update'), _('Submit changes'), ICON_UPDATE, 'default',
+                               'editor_view');
+
+               $this->_add_action('RESET', '_cancel', _('Cancel'), _('Cancel changes'), ICON_ESCAPE, 'cancel',
+                       'list_view');
+
+               if ($this->options['insert'])
+                       $this->_add_action('ADD', '_add', _('Add'), _('Add new'), ICON_ADD, 'default',
+                               'editor_view');
+
+               if ($this->options['insert'])
+                       $this->_add_action('NEW', '_add', _('New'), _('Add new'), ICON_ADD, 'default',
+                               'editor_view');
+
+               if ($this->options['clone'])
+                       $this->_add_action('CLONE', '_cloning', _('Clone'), _('Clone'), ICON_ADD, '',
+                               'editor_view');
+
+               $this->data_set = $data_set;
+               $this->fields = $data_set->fields;
+
+//             $this->_prev_status();
+       }
+
+       function _add_action($name, $handler, $but_value=null, $but_title=false, $but_icon=false, $aspect='', $view=null)
+       {
+               $this->pre_handlers[$name] = $handler;
+
+               if ($but_value)
+                       $this->tool_buttons[$name] = array($but_value, $but_title, $but_icon, $aspect);
+
+               if ($view)
+                       $this->_add_mode($name, $view);
+       }
+
+       function _add_mode($name, $view)
+       {
+               $this->views[$name] = $view;
+       }
+
+       function _prev_status()
+       {
+               // Restore previous mode/key (obsolete for views stored in session)
+
+               $mod = get_post($this->name.'Mode', $this->Mode);
+               if ($mod) {
+                       if (is_array($mod)) {
+                               $val = key($mod);
+                               $this->selected_id = $val!==null ? @quoted_printable_decode($val) : $this->_none;
+                               $mod = $mod[$val];
+                       } else {
+                               $val = $mod;
+                               $this->selected_id = $this->_none;
+                       }
+               }
+               $this->Mode = $mod;
+       }
+
+       function _check_mode()
+       {
+               global $Ajax;
+
+               $mod = '';//$this->Mode;
+               // Detect action (mode change)
+               foreach (array_keys($this->pre_handlers) as $m) { // check button controls
+
+                       if (isset($_POST[$this->name.$m])) {
+                               unset($_POST['_focus']); // focus on first form entry
+                               $Ajax->activate($this->name.'_div');
+                               $Ajax->activate($this->name.'_controls');
+                               $val = is_array($_POST[$this->name.$m]) ? key($_POST[$this->name.$m]) : null;
+                               $this->prev_id = $this->selected_id;
+                               $this->selected_id = $val!==null ? @quoted_printable_decode($val) : $this->_none;
+                               $mod = $m; break;
+                       }
+               }
+               if (!$mod && $_SERVER['REQUEST_METHOD'] == 'GET') // initialize on every GET
+                       $mod = 'RESET';
+
+               return $mod;
+       }
+
+       function display_error()
+       {
+               $this->errors = array_merge($this->data_set->errors, $this->errors);
+               $firsterr = reset($this->errors);
+               $field = key($this->errors);
+
+               if (!is_numeric($field))
+                       set_focus($this->name.$field);
+               display_error($firsterr);
+
+               $this->errors = array(); // clean up to prevent false errors on object reuse
+       }
+       //
+       //      Set record for edition
+       //
+       function _edit($mode)
+       {
+               if ($this->selected_id != $this->prev_id || $mode != $this->Mode) { // get record for edition
+                       $this->data = $this->data_set->get($this->selected_id !== $this->_none ? $this->selected_id : null);
+                       $this->set_output();
+               }
+//             if ($this->Mode != $mode) {
+//             }
+
+//             else
+//                     $this->display_error();
+
+               $this->Mode = $mode;
+       }
+       //
+       //      Update record after edition
+       //
+       function _update($mode)
+       {
+               if (!$this->options['update'])
+                       return;
+
+               $this->data = $this->get_input();
+               if ($this->data_set->update_check($this->selected_id, $this->data) && $this->data_set->update($this->selected_id, $this->data)) {
+                               $this->selected_id = $this->_none;
+                               $this->Mode = 'RESET';
+                               $this->_cancel();
+                               if (is_string($this->options['update']))
+                                       display_notification($this->options['update']);
+                               return;
+               }
+               else
+                       $this->display_error();
+
+               $this->Mode = $mode;
+       }
+       //
+       //      Add new record
+       //
+       function _add($mode)
+       {
+               if (!$this->options['insert'])
+                       return;
+
+               if ($mode == 'ADD') {
+                       $this->data = $this->get_input();
+                       if ($this->data_set->insert_check($this->data) && ($this->data_set->insert($this->data) !== false)) {
+                               $this->_cancel();
+                               if (is_string($this->options['insert']))
+                                       display_notification($this->options['insert']);
+                               $this->Mode = 'RESET';
+                               return;
+                       }
+                       else
+                               $this->display_error();
+               } else {// mode==NEW
+                               $this->data = $this->data_set->get();
+               }
+               $this->Mode = 'ADD';
+       }
+       //
+       //      Delete selected  record
+       //
+       function _delete()
+       {
+               if (!$this->options['delete'])
+                       return;
+
+               if ($this->data_set->delete_check($this->selected_id) && $this->data_set->delete($this->selected_id))
+               {
+                       if (is_string($this->options['delete']))
+                               display_notification($this->options['delete']);
+               } else
+                       $this->display_error();
+               $this->_cancel();
+       }
+       //
+       //      Return to listing view
+       //
+       function _cancel()
+       {
+               global $Ajax;
+               $this->selected_id = $this->_none;
+               if ($this->display_both)
+               {
+                       $this->data = $this->data_set->get();
+                       $this->set_output();
+               }
+               $this->cancel();
+               if (!$this->display_both)
+                       $Ajax->activate($this->name.'_div');
+               $this->Mode = 'RESET';
+       }
+       //
+       // Clone record for new edition
+       //
+       function _cloning()
+       {
+               if (!$this->options['clone'])
+                       return;
+               $this->Mode = 'ADD';
+               $this->_edit('Edit');
+               $this->selected_id = $this->_none;
+       }
+       /*
+               Generate form controls
+       */
+
+       function _record_controls($list_view = false)
+       {
+               $clone = $this->options['clone'] && $this->selected_id != $this->_none;
+
+               div_start($this->name.'_controls');
+               echo "<center>";
+
+               if ($list_view)
+                       $this->action_button('NEW');
+               else {
+                       if ($this->Mode == 'NEW' || $this->selected_id==$this->_none)
+                       {
+                               $this->action_button('ADD');
+                               $this->action_button('RESET');
+                       } else {
+                               $this->action_button('UPDATE', $this->selected_id);
+                               if ($clone && $this->display_both) 
+                                       $this->action_button('CLONE', $this->selected_id);
+                               $this->action_button('RESET');
+                       }
+               }
+
+               echo "</center>";
+               div_end();
+       }
+
+       //===========================================================================
+       // Public functions
+       //
+
+       //
+       //      Submit buttons for form actions
+       //
+       function action_button($action, $selected_id=null)
+       {
+               list($value, $title, $icon, $aspect) = $this->tool_buttons[$action];
+               submit($this->name.$action.(isset($selected_id) ? "[$selected_id]" : ''), $value, true, $title, $aspect, $icon);
+       }
+
+       //
+       //      Tool button for grid line actions.
+       //
+       function tool_button($name, $selected_id=null, $params='')
+       {
+               $b = $this->tool_buttons[$name];
+
+               return "<td align='center' $params>"
+                       .button( "{$this->name}$name"
+                               .($selected_id === null || $selected_id === $this->_none ? '': "[$selected_id]"),
+                               $b[0], $b[1], $b[2], $b[3])."</td>";
+       }
+       //
+       //      Main function - display current CRUD editor content
+       //
+       function show($Mode=null)
+       {
+               if (!isset($Mode))
+                       $Mode = $this->_check_mode(true);
+
+               div_start($this->name.'_div');
+
+               if (array_key_exists($Mode, $this->pre_handlers)) {
+                       $fun = $this->pre_handlers[$Mode];
+                       if (is_array($fun))
+                               call_user_func($fun, $Mode);
+                       else
+                               $this->$fun($Mode);
+               }
+
+               if (isset($this->views[$this->Mode]))
+                       $this->{$this->views[$this->Mode]}($Mode);
+               else
+                       $this->{$this->views['']}($Mode); // default view
+
+               // this is needed only when we use temporary crud object together with ajax screen updates
+               hidden($this->name.'Mode'.'['.$this->selected_id.']', $this->Mode);
+               div_end();
+       }
+       
+       //
+       //      Optional things like focus set performed on edition cancel.
+       //
+       function cancel()
+       {
+       }
+
+       //
+       //      Show database content in pager/table
+       //      parameter $Mode contains new mode on change, or '' otherwise
+       //
+       function list_view($Mode) {
+               display_notification(__FUNCTION__. ' is not defined...');
+       }
+
+       //
+       //      Show record editor screen content
+       //      parameter $Mode contains new mode on change, or '' otherwise
+       //
+       function editor_view($Mode) {
+               display_notification(__FUNCTION__. ' is not defined...');
+       }
+};
+
+class selector_crud_view extends simple_crud_view {
+
+       function selector_crud_view($name, $data_set = null, $options=array())
+       {
+               $this->display_both = true;
+               $this->simple_crud_view($name, $data_set, $options);
+       }
+
+       function _check_mode()
+       {
+               global $Ajax;
+
+               // list controls lookup
+               $prev_mode = $this->Mode;
+               $mod = '';
+
+               $list = $this->name.'_id';
+               $this->prev_id = $this->selected_id;
+               $this->selected_id = get_post($list);
+               if (list_updated($list)) {
+                       $Ajax->activate($this->name);
+                       $Ajax->activate($this->name.'_controls');
+                       $mod = $this->selected_id == $this->_none ? 'RESET' : 'Edit';
+               } else {
+                       $mod = simple_crud_view::_check_mode();
+               }
+
+               if ($mod != $prev_mode) {
+                       $Ajax->activate($this->name.'_controls');
+               }
+               if (get_post('_show_inactive_update'))
+               {
+                       $Ajax->activate($this->name.'_id');
+               }
+
+               $_POST[$list] = $this->selected_id;
+               return $mod;
+       }
+
+       function cancel()
+       {
+               global $Ajax;
+
+               $_POST[$this->name.'_id'] = $this->selected_id = $this->_none;
+               $Ajax->activate($this->name.'_id');
+       }
+}
+
+//
+//     Template for line table editors
+//
+
+class table_crud_view extends simple_crud_view {
+
+       var $title;
+
+       function table_crud_view($name, &$data_set = null, $options=array())
+       {
+               $this->display_both = true;
+               $this->simple_crud_view($name, $data_set, $options);
+       }
+       /**
+       *
+       *       Returns selector string from data or current selected_id
+       *
+       **/
+       function curr_id($data=null)
+       {
+               if ($data)
+                       return $data ? implode('_', array_intersect_key($data, array_fill_keys($this->key, true))) : null; // php 5.2.0
+               else
+                       return $this->selected_id;
+       }
+       /**
+       *
+       *       Show single line from record table
+       *
+       **/
+       function show_record_row($line_no, $record=array())
+       {
+/* TBD
+               $id = $this->curr_id($record); // extract key
+
+               $view = array();
+               $this->set_output($line, $view);
+
+               $editables = array();
+               if ($this->options['edit'] && $this->Mode=='Edit' && $this->selected_id==$id)
+               {
+                       $editables = $this->data_set->edit_status($key);
+               }
+               $ctrls = $this->get_field_views($record, $editables);
+               alt_table_row_color($k);
+               foreach($ctrls as $key => $fld)
+               {
+                       echo '<td>';
+                       echo $ctrls[$key];
+                       echo '</td>';
+               }
+
+               if ($this->options['edit']) {
+                       echo '<td>';
+                       $this->tool_button($this->selected_id==$id ? 'UPDATE' : 'Edit', $id);
+                       echo '</td>';
+               }
+               if ($this->options['delete']$this->selected_id==$id) {
+                       echo '<td>';
+                       $this->tool_button( ? 'Cancel' : 'Delete', $id);
+                       echo '</td>';
+               }
+               end_row();
+
+               if ($this->options['insert'])
+               {
+                       alt_table_row_color($k);
+                       $this->new_line($line_no, $line);
+                       end_row();
+               }
+*/
+       }
+       function show_list_headers()
+       {
+       }
+       //
+       //      Main function - display current CRUD table content
+       //
+       function show($Mode=null)
+       {
+               if (!isset($Mode))
+                       $Mode = $this->_check_mode(true);
+               div_start($this->name.'_div');
+
+               if (array_key_exists($Mode, $this->pre_handlers))
+               {
+                       $fun = $this->pre_handlers[$Mode];
+                       if (is_array($fun))
+                       {
+                               if (is_object($fun[0]))
+                                       $fun[0]->$fun[1]($Mode);
+                       } else
+                       $this->$fun($Mode);
+               }
+
+               if ($this->title)
+                       display_heading($this->title);
+
+               start_table(TABLESTYLE, "width=95%");
+               $this->show_list_headers();
+
+               foreach($this->data_set->get_all() as $line_no => $line) {
+                       $this->show_record_row($line_no, $line);
+               }
+               $this->show_record_row();
+
+               end_table();
+               hidden($this->name.'Mode'.'['.$this->selected_id.']', $this->Mode);
+               div_end();
+       }
+
+};
diff --git a/includes/ui/class.reflines_crud.inc b/includes/ui/class.reflines_crud.inc
new file mode 100644 (file)
index 0000000..46b4d4d
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+include_once $path_to_root.'/includes/db/class.reflines_db.inc';
+include_once $path_to_root.'/includes/ui/class.crud_view.inc';
+
+class fa_reflines extends simple_crud_view {
+
+       function fa_reflines()
+       {
+               $this->simple_crud_view('refs', new reflines_db(), array('clone' => false));
+
+               $this->fields = array(
+                       'prefix',
+                       'description',
+                       'trans_type',
+                       'pattern',
+                       'default',
+               );
+
+       }
+
+       function list_view($Mode)
+       {
+               global $Ajax, $systypes_array;
+
+               start_table(TABLESTYLE);
+
+               $th = array(_("Transaction type"), _("Prefix"),
+                       _("Pattern"), _("Default"), _("Memo"),  "", "");
+
+               inactive_control_column($th);
+
+               table_header($th);
+
+               $k = 0;
+               $data = $this->data_set->get_all(check_value('show_inactive') ? null : '!inactive', array('trans_type', 'prefix'));
+
+               if (!$data) return false;
+
+               while ($rec = db_fetch($data))
+               {
+                       alt_table_row_color($k);
+
+                       label_cell($systypes_array[$rec['trans_type']]);
+                       label_cell($rec['prefix']);
+                       label_cell($rec['pattern']);
+                       label_cell($rec['default'] ? _("Yes") : _("No"));
+                       label_cell($rec['description']);
+
+                       if (check_value('show_inactive') && $rec['default'])
+                               label_cell('');
+                       else
+                               inactive_control_cell($rec["id"], $rec["inactive"], 'reflines', 'id');
+                       if ($this->options['update'])
+                               echo $this->tool_button('Edit', $rec['id']);
+                       if ($this->options['delete']) {
+                               echo $this->tool_button('Delete', $rec['id']);
+                       }
+                       end_row();
+               }
+               inactive_control_row($th);
+               end_table(1);
+               $this->_record_controls(true);
+
+               return true;
+       }
+
+       function editor_view($Mode)
+       {
+               global $systypes_array;
+
+               $selected_id = $this->selected_id;
+
+               // new or never used
+               $fresh = $selected_id == $this->_none || !$this->data_set->is_used(get_post($this->name.'prefix'), get_post($this->name.'trans_type'));
+
+               start_table(TABLESTYLE2);
+               if ($fresh)
+               {
+                       systypes_list_row(_("Transaction Type:"), $this->name.'trans_type');
+                       $prefix = text_input($this->name.'prefix', null, 5, 30);
+               } else {
+                       label_row(_("Transaction Type:"), $systypes_array[get_post($this->name.'trans_type')]);
+                       hidden($this->name.'trans_type');
+                       $prefix = get_post($this->name.'prefix') . hidden($this->name.'prefix');
+               }
+
+               label_row(_("Reference Pattern:"), $prefix . text_input($this->name.'pattern', null, 30, 60));
+
+               if (get_post($this->name.'default'))
+                       label_row(_("Default for This Type:"), _("Yes"));
+               else
+                       check_row(_("Set as Default for This Type:"), $this->name.'default');
+
+               text_row_ex(_("Memo:"), $this->name.'description', 30, 60);
+
+               end_table(1);
+               hidden($this->name.'selected_id', $selected_id);
+               $this->_record_controls();
+       }
+
+       function show($Mode=null)
+       {
+               parent::show($Mode);
+       }
+}
index bdb7e94545bba833171ea38d60b22a969facea16..ed0e05951c333e970187de8ed512bbf2a6d59a2f 100644 (file)
@@ -709,19 +709,70 @@ function file_row($label, $name, $id = "")
        echo "</tr>\n";
 }      
 
-//-----------------------------------------------------------------------------------
+/*-----------------------------------------------------------------------------------
+
+ Reference number input.
 
-function ref_cells($label, $name, $title=null, $init=null, $params=null, $submit_on_change=false)
+ Optional  $context array contains transaction data used in number parsing:
+       'data' - data used for month/year codes
+       'location' - location code
+       'customer' - debtor_no
+       'supplier' - supplier id
+       'branch' - branch_code
+*/
+function ref_cells($label, $name, $title=null, $init=null, $params=null, $submit_on_change=false, $type=null, $context=null)
 {
-       text_cells_ex($label, $name, 16, 18, $init, $title, $params, null, $submit_on_change);
+       global $Ajax, $Refs;
+
+       if (isset($type)) {
+               if (empty($_POST[$name.'_list'])) // restore refline id
+                       $_POST[$name.'_list'] = $Refs->reflines->find_refline_id(empty($_POST[$name]) ? $init : $_POST[$name], $type);
+
+               if (empty($_POST[$name]) || ($_SERVER['REQUEST_METHOD'] == 'GET')) // initialization
+               {
+                       if (isset($init))
+                       {
+                               $_POST[$name] = $init;
+                       } else {
+                               $_POST[$name] = $Refs->get_next($type, $_POST[$name.'_list'], $context); // set default
+                       }
+                       $Ajax->addUpdate(true, $name, $_POST[$name]);
+               }
+
+               if (check_ui_refresh($name)) { // call context changed
+                       $_POST[$name] = $Refs->normalize($init, $type, $context, $_POST[$name.'_list']);
+                       $Ajax->addUpdate(true, $name, $_POST[$name]);
+               }
+
+               if ($Refs->reflines->count($type)>1) {
+                       if (list_updated($name.'_list')) {
+                               $_POST[$name] = $Refs->get_next($type, $_POST[$name.'_list'], $context);
+                               $Ajax->addUpdate(true, $name, $_POST[$name]);
+                       }
+                       $list = refline_list($name.'_list', $type);
+               } else {
+                       $list = '';
+               }
+
+               if (isset($label))
+                       label_cell($label, $params);
+
+               label_cell($list."<input name='".$name."' "
+                       .(check_edit_access($name) ? '' : 'disabled ')
+                       ."value='".@$_POST[$name]."' size=10 maxlength=35>");
+       }
+       else // just wildcard ref field (e.g. for global inquires)
+       {
+               text_cells_ex($label, $name, 16, 35, $init, $title, $params, null, $submit_on_change);
+       }
 }
 
 //-----------------------------------------------------------------------------------
 
-function ref_row($label, $name, $title=null, $init=null, $submit_on_change=false)
+function ref_row($label, $name, $title=null, $init=null, $submit_on_change=false, $type=null, $context = null)
 {
        echo "<tr><td class='label'>$label</td>";
-       ref_cells(null, $name, $title, $init, null, $submit_on_change);
+       ref_cells(null, $name, $title, $init, null, $submit_on_change, $type, $context);
        echo "</tr>\n";
 }
 
index 88b33f4fb111fa0fe4b805be208bd26ea6f4612a..bfb5c6eb3b23beadfcd58d7e1723debc09f79c68 100644 (file)
@@ -2365,6 +2365,40 @@ function tax_algorithm_list_row($label, $name, $value=null, $submit_on_change=fa
        tax_algorithm_list_cells(null, $name, $value, $submit_on_change);
        echo "</tr>\n";
 }
+
+function refline_list($name, $type, $value=null, $spec_option=false)
+{
+       $sql = "SELECT id, prefix, inactive FROM ".TB_PREF."reflines";
+
+       $where = array();
+
+       if (isset($type))
+               $where = array('`trans_type`='.db_escape($type));
+
+       return combo_input($name, $value, $sql, 'id', 'prefix',
+               array(
+                       'order'=>array('prefix'),
+                       'spec_option' => $spec_option,
+                       'spec_id' => '',
+                       'type' => 2,
+                       'where' => $where,
+                       'select_submit' => true,
+                       )
+               );
+}
+
+function refline_list_row($label, $name, $type, $selected_id=null, $spec_option=false)
+{
+       echo "<tr>";
+       if ($label != null)
+               echo "<td class='label'>$label</td>\n";
+       echo "<td>";
+
+       echo refline_list($name, $type, $selected_id, $spec_option);
+       echo "</td></tr>\n";
+}
+
+
 //----------------------------------------------------------------------------------------------
 
 function subledger_list($name, $account, $selected_id=null)
index 12883aa048ce9f237c0ceec71b9deff1a7fa3332..9c2b594f242041460dd7c1cb8438b600c5281191 100644 (file)
@@ -262,7 +262,7 @@ function check_ui_refresh($name=null)
                $name = $bt[1]['function'];
        $old = @$_SESSION['ui_context'][$name];
        $new = $_SESSION['ui_context'][$name] = $bt[1]['args'];
-       return ($new != $old) || ($_SERVER['REQUEST_METHOD'] == 'GET');
+       return ($new != $old);
 }
 
 //--------------------------------------------------------------------------------------
index 9a9a09d1b482de09f5ee9edc18e6eb68163a456e..3d2c39baf1c1fc89a3794b834887a50335e60d21 100644 (file)
@@ -87,16 +87,9 @@ function can_process()
                set_focus('stock_id');
                return false;
        }
-       if (!$Refs->is_valid($_POST['ref'])) 
-       {
-               display_error( _("You must enter a reference."));
-               set_focus('ref');
-               return false;
-       }
 
-       if (!is_new_reference($_POST['ref'], ST_INVADJUST)) 
+       if (!check_reference($_POST['ref'], ST_INVADJUST))
        {
-               display_error( _("The entered reference is already in use."));
                set_focus('ref');
                return false;
        }
index eb2f03d26da770968c5253d27758e7c6141fdedb..0bd5d2b75a22820a55b8a4e5596892bb0e57e145 100644 (file)
@@ -35,7 +35,9 @@ function display_order_header(&$order)
     date_row(_("Date:"), 'AdjDate', '', true);
 
        table_section(2, "50%");
-       ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_INVADJUST));
+
+       ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_INVADJUST, null, array('location'=>get_post('StockLocation'), 'date'=>get_post('AdjDate'))),
+                false, ST_INVADJUST);
 
        end_outer_table(1); // outer table
 }
index 8c143196475878885de54900ff6a84d947a3e73b..3fd5110a2f839afdcacdfb265354cd5c17fc7a48 100644 (file)
@@ -39,7 +39,8 @@ function display_order_header(&$order)
 
     date_row(_("Date:"), 'AdjDate', '', true);
 
-       ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_LOCTRANSFER));
+       ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_LOCTRANSFER, null, array('date'=>get_post('Adjdate'), 'location'=> get_post('FromStockLocation'))),
+                false, ST_LOCTRANSFER);
 
        end_outer_table(1); // outer table
 }
index 5315a23c64b6573d46a4d9eef46af8913dffad44..12f19d28f8682c635cc91d957e5750c7f220e4e5 100644 (file)
@@ -83,15 +83,8 @@ if (isset($_POST['Process']))
                set_focus('stock_id');
                $input_error = 1;
        }
-       if (!$Refs->is_valid($_POST['ref'])) 
+       if (!check_reference($_POST['ref'], ST_LOCTRANSFER))
        {
-               display_error(_("You must enter a reference."));
-               set_focus('ref');
-               $input_error = 1;
-       } 
-       elseif (!is_new_reference($_POST['ref'], ST_LOCTRANSFER)) 
-       {
-               display_error(_("The entered reference is already in use."));
                set_focus('ref');
                $input_error = 1;
        } 
index 8d8e1517f812bb88141c856cca74c3491d709b68..272e732825e999d593c73007b2edfacd578e0d1c 100644 (file)
@@ -107,8 +107,8 @@ function add_overhead_cost($stock_id, $qty, $date_, $costs, $adj_only=false)
                        global $Refs;
 
                        $id = get_next_trans_no(ST_JOURNAL);
-                       $ref = $Refs->get_next(ST_JOURNAL);
-                       
+                       $ref = $Refs->get_next(ST_JOURNAL, null, $date_);
+
                        $stock_gl_code = get_stock_gl_code($stock_id);
                        add_journal(ST_JOURNAL, $id, $costs, $date_, get_company_currency(), $ref);
                        $memo = "WO Overhead cost settlement JV for zero/negative respository of ".$stock_id;
@@ -163,7 +163,7 @@ function add_labour_cost($stock_id, $qty, $date_, $costs, $adj_only=false)
                        global $Refs;
 
                        $id = get_next_trans_no(ST_JOURNAL);
-                       $ref = $Refs->get_next(ST_JOURNAL);
+                       $ref = $Refs->get_next(ST_JOURNAL, null, $date_);
                        add_journal(ST_JOURNAL, $id, $costs, $date_, get_company_currency(), $ref);
 
                        $stock_gl_code = get_stock_gl_code($stock_id);
@@ -219,7 +219,7 @@ function add_issue_cost($stock_id, $qty, $date_, $costs, $adj_only=false)
                        global $Refs;
 
                        $id = get_next_trans_no(ST_JOURNAL);
-                       $ref = $Refs->get_next(ST_JOURNAL);
+                       $ref = $Refs->get_next(ST_JOURNAL, null, $date_);
                        add_journal(ST_JOURNAL, $id, $costs, $date_, get_company_currency(), $ref);
                        
                        $stock_gl_code = get_stock_gl_code($stock_id);
@@ -265,7 +265,7 @@ function add_wo_costs_journal($wo_id, $amount, $cost_type, $cr_acc, $db_acc, $da
        begin_transaction();
 
     $journal_id = get_next_trans_no(ST_JOURNAL);
-    if (!$ref) $ref = $Refs->get_next(ST_JOURNAL);
+    if (!$ref) $ref = $Refs->get_next(ST_JOURNAL, null, $date);
 
        add_gl_trans_std_cost(ST_JOURNAL, $journal_id, $date, $cr_acc,
                0, 0, $wo_cost_types[$cost_type], -$amount);
index d5e8eb806ddae899dd65ca18757f0b634c8ae23c..540a57b88fe805a0841bb64b05476fb923fa15fa 100644 (file)
@@ -160,7 +160,11 @@ function issue_options_controls()
 
        echo "<br>";
        start_table();
-    ref_row(_("Reference:"), 'ref', '', $Refs->get_next(28));
+       date_row(_("Issue Date:"), 'date_');
+       locations_list_row(_("From Location:"), 'Location');
+       workcenter_list_row(_("To Work Centre:"), 'WorkCentre');
+
+    ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_MANUISSUE, null, array('date'=> get_post('date_'), 'location' => get_post('Location'));
  
        if (!isset($_POST['IssueType']))
                $_POST['IssueType'] = 0;
@@ -168,10 +172,7 @@ function issue_options_controls()
        yesno_list_row(_("Type:"), 'IssueType', $_POST['IssueType'],
                _("Return Items to Location"), _("Issue Items to Work order"));
  
-       locations_list_row(_("From Location:"), 'Location');
-       workcenter_list_row(_("To Work Centre:"), 'WorkCentre');
  
-       date_row(_("Issue Date:"), 'date_');
 
        textarea_row(_("Memo"), 'memo_', null, 50, 3);
 
index fefbf1b5eb8abc83e216201f4059171e56d87e23..8a9947a401a9e16e2e61f731a39cc3161e78773f 100644 (file)
@@ -71,16 +71,8 @@ function can_process($wo_details)
 {
        global $SysPrefs, $Refs;
 
-       if (!$Refs->is_valid($_POST['ref']))
+       if (!check_reference($_POST['ref'], ST_MANURECEIVE))
        {
-               display_error(_("You must enter a reference."));
-               set_focus('ref');
-               return false;
-       }
-
-       if (!is_new_reference($_POST['ref'], 29))
-       {
-               display_error(_("The entered reference is already in use."));
                set_focus('ref');
                return false;
        }
@@ -191,7 +183,8 @@ if (!isset($_POST['quantity']) || $_POST['quantity'] == '')
 start_table(TABLESTYLE2);
 br();
 
-ref_row(_("Reference:"), 'ref', '', $Refs->get_next(29));
+ref_row(_("Reference:"), 'ref', '', $Refs->get_next(29, null, get_post('date_')), false, ST_MANUISSUE);
+date_row(_("Date:"), 'date_');
 
 if (!isset($_POST['ProductionType']))
        $_POST['ProductionType'] = 1;
@@ -201,8 +194,6 @@ yesno_list_row(_("Type:"), 'ProductionType', $_POST['ProductionType'],
 
 small_qty_row(_("Quantity:"), 'quantity', null, null, null, $dec);
 
-date_row(_("Date:"), 'date_');
-
 textarea_row(_("Memo:"), 'memo_', null, 40, 3);
 
 end_table(1);
index df0ea0583ae081eea5b852fc7ede0129ce44d35e..a76c5f5e0d90163e5affd6def3a226f039d34fdc 100644 (file)
@@ -117,7 +117,7 @@ display_wo_details($_POST['selected_id']);
 //-------------------------------------------------------------------------------------
 
 if (!isset($_POST['ref']))
-       $_POST['ref'] = $Refs->get_next(ST_JOURNAL);
+       $_POST['ref'] = $Refs->get_next(ST_JOURNAL, null, get_post('date_'));
 
 start_form();
 
index ccc2635e3ecb86dbb458e85f10862d21df4182d0..6a27bfc2eb3df89e845d4cdcb60fdfb7ee3fa107 100644 (file)
@@ -126,16 +126,8 @@ function can_process()
 
        if (!isset($selected_id))
        {
-       if (!$Refs->is_valid($_POST['wo_ref']))
+       if (!check_reference($_POST['wo_ref'], ST_WORKORDER))
        {
-               display_error(_("You must enter a reference."));
-                       set_focus('wo_ref');
-               return false;
-       }
-
-       if (!is_new_reference($_POST['wo_ref'], ST_WORKORDER))
-       {
-               display_error(_("The entered reference is already in use."));
                        set_focus('wo_ref');
                return false;
        }
@@ -380,7 +372,7 @@ if (isset($selected_id))
 else
 {
        $_POST['units_issued'] = $_POST['released'] = 0;
-       ref_row(_("Reference:"), 'wo_ref', '', $Refs->get_next(ST_WORKORDER));
+       ref_row(_("Reference:"), 'wo_ref', '', $Refs->get_next(ST_WORKORDER, null, get_post('date_')), false, ST_WORKORDER);
 
        wo_types_list_row(_("Type:"), 'type', null);
 }
index dfe11060557d844b293b7003ffd3a7d1f4075d00..86e3677aa6670923d46ad71cc57e72a7d34fe933 100644 (file)
@@ -73,28 +73,20 @@ function can_process()
 {
        global $Refs;
 
-       if (!is_date($_POST['date_'])) 
+       if (!is_date($_POST['date_']))
        {
                display_error(_("The entered date for the issue is invalid."));
                set_focus('date_');
                return false;
        } 
-       elseif (!is_date_in_fiscalyear($_POST['date_'])) 
+       elseif (!is_date_in_fiscalyear($_POST['date_']))
        {
                display_error(_("The entered date is out of fiscal year or is closed for further data entry."));
                set_focus('date_');
                return false;
        }
-       if (!$Refs->is_valid($_POST['ref'])) 
+       if (!check_reference($_POST['ref'], ST_MANUISSUE))
        {
-               display_error(_("You must enter a reference."));
-               set_focus('ref');
-               return false;
-       }
-
-       if (!is_new_reference($_POST['ref'], ST_MANUISSUE)) 
-       {
-               display_error(_("The entered reference is already in use."));
                set_focus('ref');
                return false;
        }
index 543df442ce77c51ae1081256879220205e2bb129..11ce9f931ca33d0c4835a8c9184c5600055ab0fa 100644 (file)
@@ -597,7 +597,7 @@ function void_supp_invoice($type, $type_no)
 
                                                //Chaitanya : Post a journal entry
                                                $id = get_next_trans_no(ST_JOURNAL);
-                                               $ref = $Refs->get_next(ST_JOURNAL);
+                                               $ref = $Refs->get_next(ST_JOURNAL, null, $date_);
                                                add_journal(ST_JOURNAL, $id, $details_row["quantity"] * $diff, $old_date, get_company_currency(), $ref);
                                                $stock_id = $details_row["stock_id"];
                                                $stock_gl_code = get_stock_gl_code($stock_id);
index 7b18d6ca13a9a75e129c65f59ddf44581e84a7f6..983085769894f972b327eda71eae97da4fc9dc34 100644 (file)
@@ -211,7 +211,7 @@ function add_direct_supp_trans($cart)
        $inv_no = add_supp_invoice($inv);
 
        if ($cart->cash_account) {
-               $pmt_no = write_supp_payment(0, $inv->supplier_id, $cart->cash_account, $inv->tran_date, $Refs->get_next(ST_SUPPAYMENT), 
+               $pmt_no = write_supp_payment(0, $inv->supplier_id, $cart->cash_account, $inv->tran_date, $Refs->get_next(ST_SUPPAYMENT, null, $inv->tran_date), 
                        $total, 0, _('Payment for:').$inv->supp_reference .' ('.$type_shortcuts[ST_SUPPINVOICE].$inv_no.')');
                add_supp_allocation($total, ST_SUPPAYMENT, $pmt_no, ST_SUPPINVOICE, $inv_no, $inv->supplier_id, $inv->tran_date);
                update_supp_trans_allocation(ST_SUPPINVOICE, $inv_no, $inv->supplier_id);
index 4ac5c5bc2a7b570d3e360d42bcf04b4c9b5602c4..5d2c25a2bc5ebe5437eecb527bc7ae0d7655c8e2 100644 (file)
@@ -60,7 +60,7 @@ function edit_grn_summary(&$po)
 
        table_section(2);
        if (!isset($_POST['ref']))
-           $_POST['ref'] = $Refs->get_next(ST_SUPPRECEIVE);
+           $_POST['ref'] = $Refs->get_next(ST_SUPPRECEIVE, null, array('supplier' => $po->supplier_id, 'date' => Today()));
        ref_row(_("Reference"), 'ref', '', null);
 
         if (!isset($_POST['Location']))
index 1da839bbc1bab8fe48de5c3d881f7319c81ec802..6c799b44f7e4b9c50168cff13ccc70c8a62afaf0 100644 (file)
@@ -117,7 +117,10 @@ function invoice_header(&$supp_trans)
                copy_from_trans($supp_trans);
        }
 
-       ref_row(_("Reference:"), 'reference', '', $Refs->get_next($supp_trans->trans_type));
+       date_row(_("Date") . ":", 'tran_date', '', true, 0, 0, 0, "", true);
+
+       ref_row(_("Reference:"), 'reference', '', $Refs->get_next($supp_trans->trans_type, null, 
+               array('supplier' => get_post('supplier_id'), 'date' => get_post('tran_date'))), false, $supp_trans->trans_type);
 
        if ($supp_trans->trans_type == ST_SUPPCREDIT)
        {
@@ -133,7 +136,6 @@ function invoice_header(&$supp_trans)
 
        table_section(2, "33%");
 
-       date_row(_("Date") . ":", 'tran_date', '', true, 0, 0, 0, "", true);
        if (isset($_POST['_tran_date_changed'])) {
                $Ajax->activate('_ex_rate');
                $supp_trans->tran_date = $_POST['tran_date'];
index 67ce8676ab75f3d8600fd641a2d1b29bcc0a94a0..ae063b6ec4977e510b1d9dbb40db7b10db2fda62 100644 (file)
@@ -84,7 +84,8 @@ function create_new_po($trans_type, $trans_no)
                read_po($trans_no, $cart);
                $cart->order_no = $trans_no;
        } else
-               $cart->reference = $Refs->get_next($trans_type);
+               $cart->reference = $Refs->get_next($trans_type, null,
+                       array('supplier_id' => $cart->supplier_id, 'date' => get_post('OrderDate')));
        $_SESSION['PO'] = &$cart;
 }
 
index 17e123f9c6f891a54bd3c4e85e134d686de29792..a4afb367dce2194cc7c1b7e12c243770ec64ed1d 100644 (file)
@@ -353,22 +353,14 @@ function can_commit()
 
        if (!$_SESSION['PO']->order_no) 
        {
-       if (!$Refs->is_valid(get_post('ref'))) 
+       if (!check_reference(get_post('ref'), $_SESSION['PO']->trans_type))
        {
-               display_error(_("There is no reference entered for this purchase order."));
-                       set_focus('ref');
-               return false;
-       } 
-
-       if (!is_new_reference(get_post('ref'), $_SESSION['PO']->trans_type)) 
-       {
-               display_error(_("The entered reference is already in use."));
                        set_focus('ref');
                return false;
        }
        }
 
-       if ($_SESSION['PO']->trans_type == ST_SUPPINVOICE && !$Refs->is_valid(get_post('supp_ref'))) 
+       if ($_SESSION['PO']->trans_type == ST_SUPPINVOICE && empty(trim(get_post('supp_ref'))))
        {
                display_error(_("You must enter a supplier's invoice reference."));
                set_focus('supp_ref');
index da277b2743366586c44f922f6342098004200ceb..0ea2cef12b36f9609ae01850af97cf3ac9d5cdc6 100644 (file)
@@ -181,16 +181,8 @@ function can_process()
                return false;
        }
 
-    if (!$Refs->is_valid($_POST['ref']))
-    {
-               display_error(_("You must enter a reference."));
-               set_focus('ref');
-               return false;
-       }
-
-       if (!is_new_reference($_POST['ref'], ST_SUPPRECEIVE))
+       if (!check_reference($_POST['ref'], ST_SUPPRECEIVE))
        {
-               display_error(_("The entered reference is already in use."));
                set_focus('ref');
                return false;
        }
@@ -281,7 +273,8 @@ if (isset($_GET['PONumber']) && $_GET['PONumber'] > 0 && !isset($_POST['Update']
 {
        create_new_po(ST_PURCHORDER, $_GET['PONumber']);
        $_SESSION['PO']->trans_type = ST_SUPPRECEIVE;
-       $_SESSION['PO']->reference = $Refs->get_next(ST_SUPPRECEIVE);
+       $_SESSION['PO']->reference = $Refs->get_next(ST_SUPPRECEIVE, 
+               array('date' => $_SESSION['PO']->tran_date, 'supplier' => $_SESSION['PO']->supplier_id));
        copy_from_cart();
 }
 
index c2fe7c6113f9d7cfcdb62c792b55392903396107..19337cbef13a094288de4dba7eca5b08cf439cf5 100644 (file)
@@ -170,27 +170,12 @@ function check_data()
                return false;
        }
 
-       if (!$Refs->is_valid($_SESSION['supp_trans']->reference)) 
+       if (!check_reference($_SESSION['supp_trans']->reference, ST_SUPPCREDIT, $_SESSION['supp_trans']->trans_no))
        {
-               display_error(_("You must enter an credit note reference."));
                set_focus('reference');
                return false;
        }
 
-       if (!is_new_reference($_SESSION['supp_trans']->reference, ST_SUPPCREDIT, $_SESSION['supp_trans']->trans_no))
-       {
-               display_error(_("The entered reference is already in use."));
-               set_focus('reference');
-               return false;
-       }
-
-       if (!$Refs->is_valid($_SESSION['supp_trans']->supp_reference)) 
-       {
-               display_error(_("You must enter a supplier's credit note reference."));
-               set_focus('supp_reference');
-               return false;
-       }
-
        if (!is_date($_SESSION['supp_trans']->tran_date))
        {
                display_error(_("The credit note as entered cannot be processed because the date entered is not valid."));
index 696cd6d67c1387d85a944456055a58c3cfa1969c..faf540e334c19c4cd261c4c7b9f55e986c726559 100644 (file)
@@ -178,27 +178,12 @@ function check_data()
                return false;
        }
 
-       if (!$Refs->is_valid($_SESSION['supp_trans']->reference)) 
+       if (!check_reference($_SESSION['supp_trans']->reference, ST_SUPPINVOICE, $_SESSION['supp_trans']->trans_no))
        {
-               display_error(_("You must enter an invoice reference."));
                set_focus('reference');
                return false;
        }
 
-       if (!is_new_reference($_SESSION['supp_trans']->reference, ST_SUPPINVOICE, $_SESSION['supp_trans']->trans_no))
-       {
-               display_error(_("The entered reference is already in use."));
-               set_focus('reference');
-               return false;
-       }
-
-       if (!$Refs->is_valid($_SESSION['supp_trans']->supp_reference)) 
-       {
-               display_error(_("You must enter a supplier's invoice reference."));
-               set_focus('supp_reference');
-               return false;
-       }
-
        if (!is_date( $_SESSION['supp_trans']->tran_date))
        {
                display_error(_("The invoice as entered cannot be processed because the invoice date is in an incorrect format."));
index 955bd23ca331d4ec822cb33d342c84768cbe51d2..323ff16ec6f1911906e9ecefe7a5ce47cc5ef7ae 100644 (file)
@@ -202,16 +202,8 @@ function check_inputs()
                return false;
        }
 
-    if (!$Refs->is_valid($_POST['ref'])) 
-    {
-               display_error(_("You must enter a reference."));
-               set_focus('ref');
-               return false;
-       }
-
-       if (!is_new_reference($_POST['ref'], ST_SUPPAYMENT)) 
+       if (!check_reference($_POST['ref'], ST_SUPPAYMENT))
        {
-               display_error(_("The entered reference is already in use."));
                set_focus('ref');
                return false;
        }
@@ -295,7 +287,9 @@ start_form();
 
     date_row(_("Date Paid") . ":", 'DatePaid', '', true, 0, 0, 0, null, true);
 
-    ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_SUPPAYMENT));
+    ref_row(_("Reference:"), 'ref', '', $Refs->get_next(ST_SUPPAYMENT, null, 
+       array('supplier'=>get_post('supplier_id'), 'date'=>get_post('DatePaid'))), false, ST_SUPPAYMENT);
+
 
        table_section(3);
 
index 0d71d9d4dbb4eecfc5b357bfd77cc21d7d0d7174..de93bd5c7d968e669c8bdb6672df84276b54e97b 100644 (file)
@@ -38,7 +38,8 @@ function create_recurrent_invoices($customer_id, $branch_id, $order_no, $tmpl_no
        $doc->document_date = $date; 
 
        $doc->due_date = get_invoice_duedate($doc->payment, $doc->document_date);
-       $doc->reference = $Refs->get_next($doc->trans_type);
+       $doc->reference = $Refs->get_next($doc->trans_type, null, array('customer' => $customer_id, 'branch' => $branch_id,
+               'date' => $date));
        if ($doc->Comments != "")
                $doc->Comments .= "\n";
        $doc->Comments .= sprintf(_("Recurrent Invoice covers period %s - %s."), $from, add_days($to, -1));
@@ -50,7 +51,8 @@ function create_recurrent_invoices($customer_id, $branch_id, $order_no, $tmpl_no
        }       
        $cart = $doc;
        $cart->trans_type = ST_SALESINVOICE;
-       $cart->reference = $Refs->get_next($cart->trans_type);
+       $cart->reference = $Refs->get_next($cart->trans_type, null, array('customer' => $customer_id, 'branch' => $branch_id,
+               'date' => $date));
        $invno = $cart->write(1);
        if ($invno == -1)
        {
index 8181f7a34c24c3e1154af1642676bb1f622109c1..98fd6c1e0b6c9d997f72a167efdcbd12b3ed3f96 100644 (file)
@@ -143,7 +143,7 @@ function can_process()
        if ($_SESSION['Items']->count_items() == 0 && (!check_num('ChargeFreightCost',0)))
                return false;
        if($_SESSION['Items']->trans_no == 0) {
-           if (!$Refs->is_valid($_POST['ref'])) {
+           if (!$Refs->is_valid($_POST['ref'], ST_CUSTCREDIT)) {
                        display_error( _("You must enter a reference."));
                        set_focus('ref');
                        $input_error = 1;
index 7cf3856d0c50090755aff89816ad432935b2ef04..bb1445be6eb11a39380d2446b7bede53931ecf90 100644 (file)
@@ -97,7 +97,7 @@ function can_process()
        }
 
     if ($_SESSION['Items']->trans_no==0) {
-               if (!$Refs->is_valid($_POST['ref'])) {
+               if (!$Refs->is_valid($_POST['ref'], ST_CUSTCREDIT)) {
                        display_error(_("You must enter a reference."));;
                        set_focus('ref');
                        return false;
@@ -241,7 +241,10 @@ function display_credit_items()
 //             $_POST['ref'] = $Refs->get_next(11);
 
     if ($_SESSION['Items']->trans_no==0) {
-               ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
+               ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'", false, ST_CUSTCREDIT,
+               array('customer' => $_SESSION['Items']->customer_id,
+                       'branch' => $_SESSION['Items']->Branch,
+                       'date' => get_post('CreditDate')));
        } else {
                label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
        }
index a49c5c55c236c5a0d95156f9fd44ba8e15740eac..767fd7c2910104164a4b72bac6a59e5fad8b48be 100644 (file)
@@ -173,7 +173,7 @@ function check_data()
        }
 
        if ($_SESSION['Items']->trans_no==0) {
-               if (!$Refs->is_valid($_POST['ref'])) {
+               if (!$Refs->is_valid($_POST['ref'], ST_CUSTDELIVERY)) {
                        display_error(_("You must enter a reference."));
                        set_focus('ref');
                        return false;
@@ -333,7 +333,10 @@ start_row();
 //     $_POST['ref'] = $Refs->get_next(ST_CUSTDELIVERY);
 
 if ($_SESSION['Items']->trans_no==0) {
-       ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
+       ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'", false, ST_CUSTDELIVERY,
+       array('customer' => $_SESSION['Items']->customer_id,
+                       'branch' => $_SESSION['Items']->Branch,
+                       'date' => get_post('DispatchDate'));
 } else {
        label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
 }
index ec42340284cd6beb9034caa4dcc067dae6bb711e..10993cc040cd73cf76e91f54e3f59c8abf97f2d9 100644 (file)
@@ -331,7 +331,7 @@ function check_data()
        }
 
        if ($_SESSION['Items']->trans_no == 0) {
-               if (!$Refs->is_valid($_POST['ref'])) {
+               if (!$Refs->is_valid($_POST['ref'], ST_SALESINVOICE)) {
                        display_error(_("You must enter a reference."));
                        set_focus('ref');
                        return false;
@@ -460,7 +460,10 @@ end_row();
 start_row();
 
 if ($_SESSION['Items']->trans_no == 0) {
-       ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'");
+       ref_cells(_("Reference"), 'ref', '', null, "class='tableheader2'", false, ST_SALESINVOICE,
+               array('customer' => $_SESSION['Items']->customer_id,
+                       'branch' => $_SESSION['Items']->Branch,
+                       'date' => get_post('InvoiceDate')));
 } else {
        label_cells(_("Reference"), $_SESSION['Items']->reference, "class='tableheader2'");
 }
index c2f09eff56da7a50d62f1974539cea2b7fb1717e..10742c88dac54381fc360a932bd108ab593dfc98 100644 (file)
@@ -159,22 +159,7 @@ function can_process()
                return false;
        }
 
-       if (!$Refs->is_valid($_POST['ref'])) {
-               display_error(_("You must enter a reference."));
-               set_focus('ref');
-               return false;
-       }
-
-       //Chaitanya : 13-OCT-2011 - To support Edit feature
-       if (isset($_POST['trans_no']) && $_POST['trans_no'] == 0 && (!is_new_reference($_POST['ref'], ST_CUSTPAYMENT))) {
-               display_error(_("The entered reference is already in use."));
-               set_focus('ref');
-               return false;
-       }
-       //Avoid duplicate reference while modifying
-       elseif ($_POST['ref'] != $_POST['old_ref'] && !is_new_reference($_POST['ref'], ST_CUSTPAYMENT))
-       {
-               display_error( _("The entered reference is already in use."));
+       if (!check_reference($_POST['ref'], ST_CUSTPAYMENT, @$_POST['trans_no'])) {
                set_focus('ref');
                return false;
        }
@@ -281,12 +266,12 @@ function read_customer_data()
        //Chaitanya : 13-OCT-2011 - To support Edit feature
        //If page is called first time and New entry fetch the nex reference number
        if (!$_SESSION['alloc']->trans_no && !isset($_POST['charge'])) 
-               $_POST['ref'] = $Refs->get_next(ST_CUSTPAYMENT);
+               $_POST['ref'] = $Refs->get_next(ST_CUSTPAYMENT, null, array(
+                       'customer' => get_post('customer_id'), 'date' => get_post('DateBanked')));
 }
 
 //----------------------------------------------------------------------------------------------
 $new = 1;
-$old_ref = 0;
 
 //Chaitanya : 13-OCT-2011 - To support Edit feature
 if (isset($_GET['trans_no']) && $_GET['trans_no'] > 0 )
@@ -300,7 +285,6 @@ if (isset($_GET['trans_no']) && $_GET['trans_no'] > 0 )
        $_POST['BranchID'] = $myrow["branch_code"];
        $_POST['bank_account'] = $myrow["bank_act"];
        $_POST['ref'] =  $myrow["reference"];
-       $old_ref = $myrow["reference"];
        $charge = get_cust_bank_charge(ST_CUSTPAYMENT, $_POST['trans_no']);
        $_POST['charge'] =  price_format($charge);
        $_POST['DateBanked'] =  sql2date($myrow['tran_date']);
@@ -324,7 +308,6 @@ $new = !$_SESSION['alloc']->trans_no;
 start_form();
 
        hidden('trans_no');
-       hidden('old_ref', $old_ref);
 
        start_outer_table(TABLESTYLE2, "width='60%'", 5);
 
index dbfd51061b186a34ff5eb05779166f18f2263237..3bfb9526f1e6c0fddb33a4c2dc4577bde022fdca 100644 (file)
@@ -135,7 +135,8 @@ class cart
                        $type = get_child_type($this->trans_type);
 
                $this->trans_type = $type;
-               $this->reference = $Refs->get_next($this->trans_type);
+               $this->reference = $Refs->get_next($this->trans_type, null, array('date' => $this->document_date,
+                       'customer' => $this->customer_id, 'branch' => $this->Branch));
                if ($type == ST_CUSTCREDIT)
                    $this->src_date = $this->document_date;
 
@@ -244,7 +245,8 @@ class cart
                                $this->document_date = new_doc_date();
                                if (!is_date_in_fiscalyear($this->document_date))
                                        $this->document_date = end_fiscalyear();
-                               $this->reference = $Refs->get_next($this->trans_type);
+                               $this->reference = $Refs->get_next($this->trans_type, null, array('date' => Today(),
+                                       'customer' => $this->customer_id));
                                if ($type != ST_SALESORDER && $type != ST_SALESQUOTE) // Added 2.1 Joe Hunt 2008-11-12
                                {
                                        $dim = get_company_pref('use_dimension');
index c944c6bf656ed47976380ea1bc199d7f47cd0534..4028233e78f11f97818b4fffeb57f8917bcd44b8 100644 (file)
@@ -195,7 +195,9 @@ function write_sales_invoice(&$invoice)
                        $discount = 0; // $invoice->cash_discount*$amount;
                        $pmtno = write_customer_payment(0, $invoice->customer_id, 
                                $invoice->Branch, $invoice->pos['pos_account'], $date_,
-                               $Refs->get_next(ST_CUSTPAYMENT), $amount-$discount, $discount,
+                               $Refs->get_next(ST_CUSTPAYMENT, null, array('customer' => $invoice->customer_id,
+                                       'branch' => $invoice->Branch, 'date' => $date_)),
+                               $amount-$discount, $discount,
                                _('Cash invoice').' '.$invoice_no);
                        add_cust_allocation($amount, ST_CUSTPAYMENT, $pmtno, ST_SALESINVOICE, $invoice_no, $invoice->customer_id, $date_);
 
index ff61aaa5eef5b8c091a48ef38a43c2741131fa52..9a683f1e8fe19bbffe47a0821e08de3cb03ff872 100644 (file)
@@ -98,8 +98,6 @@ function delete_sales_order($order_no, $trans_type)
                .db_escape($order_no) . " AND trans_type=".db_escape($trans_type);
        db_query($sql, "order Detail Delete");
 
-       delete_reference($trans_type, $order_no);
-
        add_audit_trail($trans_type, $order_no, Today(), _("Deleted."));
        commit_transaction();
 }
index 0bbd100e01fb795785315d729245126e48b29d44..627358ecc4059c9c44c913d6eeb0dd62d01b717a 100644 (file)
@@ -80,7 +80,8 @@ function display_credit_header(&$order)
        set_global_customer($_POST['customer_id']);
 
        if (!isset($_POST['ref']))
-               $_POST['ref'] = $Refs->get_next(ST_CUSTCREDIT);
+               $_POST['ref'] = $Refs->get_next(ST_CUSTCREDIT, null, array('customer' => get_post('customer_id'),
+                       'branch' => get_post('branch_id'), 'date' => get_post('OrderDate'));
        if ($order->trans_no==0)
            ref_row(_("Reference").':', 'ref');
        else
index a515859b0a9cbcd2149d732b23ad2a3cdf306483..043d2514b5d2d4184576f84cb53d0dc44316b578 100644 (file)
@@ -361,7 +361,7 @@ function display_order_header(&$order, $editable, $date_text)
                }
        }
 
-       ref_row(_("Reference").':', 'ref', _('Reference number unique for this document type'), null, '');
+       ref_row(_("Reference").':', 'ref', _('Reference number unique for this document type'), null, '', $order->trans_type, array('date'=> @$_POST['OrderDate']));
 
        table_section(2);
 
index b608c2001bd06935541ae628bc035ee34888e38a..f3e84af7aeca494dc06d25e2a938c6e7f9796047 100644 (file)
@@ -431,7 +431,7 @@ function can_process() {
                        return false;
                }       
        }       
-       if (!$Refs->is_valid($_POST['ref'])) {
+       if (!$Refs->is_valid($_POST['ref'], $_SESSION['Items']->trans_type)) {
                display_error(_("You must enter a reference."));
                set_focus('ref');
                return false;
@@ -462,7 +462,7 @@ if (isset($_POST['ProcessOrder']) && can_process()) {
        if ($ret == -1)
        {
                display_error(_("The entered reference is already in use."));
-               $ref = get_next_reference($_SESSION['Items']->trans_type);
+               $ref = $Refs->get_next($_SESSION['Items']->trans_type, null, array('date' => Today()));
                if ($ref != $_SESSION['Items']->reference)
                {
                        display_error(_("The reference number field has been increased. Please save the document again."));
@@ -658,7 +658,7 @@ function create_cart($type, $trans_no)
                        $doc->pos = get_sales_point(user_pos());
                } else
                        $doc->due_date = $doc->document_date;
-               $doc->reference = $Refs->get_next($doc->trans_type);
+               $doc->reference = $Refs->get_next($doc->trans_type, null, array('date' => Today()));
                //$doc->Comments='';
                foreach($doc->line_items as $line_no => $line) {
                        $doc->line_items[$line_no]->qty_done = 0;
index 56aa0199921e65a71d08d8b0ec2c8f0d3723a4d3..2e765bfb9916b8129bd09b33ad8ce9a02b219abb 100644 (file)
@@ -240,3 +240,20 @@ UPDATE `0_salesman`
        SET `break_pt` = `break_pt`*100.0/`provision`
 WHERE `provision` != 0;
 
+# reference lines
+DROP TABLE IF EXISTS `0_reflines`;
+CREATE TABLE `0_reflines` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `trans_type` int(11) NOT NULL,
+  `prefix` char(5) NOT NULL DEFAULT '',
+  `pattern` varchar(35) NOT NULL DEFAULT '1',
+  `description` varchar(60) NOT NULL DEFAULT '',
+  `default` tinyint(1) NOT NULL DEFAULT '0',
+  `inactive` tinyint(1) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `prefix` (`trans_type`, `prefix`)
+) ENGINE=InnoDB;
+
+INSERT INTO `0_reflines` (`trans_type`, `pattern`, `default`) SELECT `type_id`, `next_reference`, 1 FROM `0_sys_types`;
+
+DROP TABLE `0_sys_types`;
index 2540c7bc09e6250ffd07b704d1d85e2dd80d2841..ba10cf959db174d8ff7d287e6a68be197b493fee 100644 (file)
@@ -1465,6 +1465,48 @@ CREATE TABLE IF NOT EXISTS `0_recurrent_invoices` (
 --
 
 
+--- Structure of table `0_reflines`
+
+DROP TABLE IF EXISTS `0_reflines`;
+
+CREATE TABLE `0_reflines` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `trans_type` int(11) NOT NULL,
+  `prefix` char(5) NOT NULL DEFAULT '',
+  `pattern` varchar(35) NOT NULL DEFAULT '1',
+  `description` varchar(60) NOT NULL DEFAULT '',
+  `default` tinyint(1) NOT NULL DEFAULT '0',
+  `inactive` tinyint(1) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `prefix` (`trans_type`, `prefix`)
+) ENGINE=InnoDB AUTO_INCREMENT=23;
+
+--- Data of table `0_reflines`
+
+INSERT INTO `0_reflines` VALUES
+('1', '0', '', '{001}/{YYYY}', '', '1', '0'),
+('2', '1', '', '{001}/{YYYY}', '', '1', '0'),
+('3', '2', '', '{001}/{YYYY}', '', '1', '0'),
+('4', '4', '', '{001}/{YYYY}', '', '1', '0'),
+('5', '10', '', '{001}/{YYYY}', '', '1', '0'),
+('6', '11', '', '{001}/{YYYY}', '', '1', '0'),
+('7', '12', '', '{001}/{YYYY}', '', '1', '0'),
+('8', '13', '', '{001}/{YYYY}', '', '1', '0'),
+('9', '16', '', '{001}/{YYYY}', '', '1', '0'),
+('10', '17', '', '{001}/{YYYY}', '', '1', '0'),
+('11', '18', '', '{001}/{YYYY}', '', '1', '0'),
+('12', '20', '', '{001}/{YYYY}', '', '1', '0'),
+('13', '21', '', '{001}/{YYYY}', '', '1', '0'),
+('14', '22', '', '{001}/{YYYY}', '', '1', '0'),
+('15', '25', '', '{001}/{YYYY}', '', '1', '0'),
+('16', '26', '', '{001}/{YYYY}', '', '1', '0'),
+('17', '28', '', '{001}/{YYYY}', '', '1', '0'),
+('18', '29', '', '{001}/{YYYY}', '', '1', '0'),
+('19', '30', '', '{001}/{YYYY}', '', '1', '0'),
+('20', '32', '', '{001}/{YYYY}', '', '1', '0'),
+('21', '35', '', '{001}/{YYYY}', '', '1', '0'),
+('22', '40', '', '{001}/{YYYY}', '', '1', '0');
+
 -- --------------------------------------------------------
 
 --
@@ -2095,48 +2137,6 @@ INSERT INTO `0_sys_prefs` VALUES('print_item_images_on_quote','glsetup.inventory
 INSERT INTO `0_sys_prefs` VALUES('alternative_tax_include_on_docs','setup.company', 'tinyint', 1, '0');
 INSERT INTO `0_sys_prefs` VALUES('suppress_tax_rates','setup.company', 'tinyint', 1, '0');
 
-
--- --------------------------------------------------------
-
---
--- Table structure for table `0_sys_types`
---
-
-DROP TABLE IF EXISTS `0_sys_types`;
-CREATE TABLE IF NOT EXISTS `0_sys_types` (
-  `type_id` smallint(6) NOT NULL default '0',
-  `type_no` int(11) NOT NULL default '1',
-  `next_reference` varchar(100) NOT NULL default '',
-  PRIMARY KEY  (`type_id`)
-) ENGINE=InnoDB;
-
---
--- Dumping data for table `0_sys_types`
---
-
-INSERT INTO `0_sys_types` VALUES(0, 19, '3');
-INSERT INTO `0_sys_types` VALUES(1, 8, '2');
-INSERT INTO `0_sys_types` VALUES(2, 5, '2');
-INSERT INTO `0_sys_types` VALUES(4, 3, '1');
-INSERT INTO `0_sys_types` VALUES(10, 19, '4');
-INSERT INTO `0_sys_types` VALUES(11, 3, '2');
-INSERT INTO `0_sys_types` VALUES(12, 6, '1');
-INSERT INTO `0_sys_types` VALUES(13, 5, '2');
-INSERT INTO `0_sys_types` VALUES(16, 2, '1');
-INSERT INTO `0_sys_types` VALUES(17, 2, '1');
-INSERT INTO `0_sys_types` VALUES(18, 1, '3');
-INSERT INTO `0_sys_types` VALUES(20, 8, '3');
-INSERT INTO `0_sys_types` VALUES(21, 1, '1');
-INSERT INTO `0_sys_types` VALUES(22, 4, '2');
-INSERT INTO `0_sys_types` VALUES(25, 1, '2');
-INSERT INTO `0_sys_types` VALUES(26, 1, '8');
-INSERT INTO `0_sys_types` VALUES(28, 1, '1');
-INSERT INTO `0_sys_types` VALUES(29, 1, '2');
-INSERT INTO `0_sys_types` VALUES(30, 5, '6');
-INSERT INTO `0_sys_types` VALUES(32, 0, '1');
-INSERT INTO `0_sys_types` VALUES(35, 1, '1');
-INSERT INTO `0_sys_types` VALUES(40, 1, '3');
-
 -- --------------------------------------------------------
 
 --
index 27ec7b3a71a723b3015cb6654f666e3ed02ad24b..1c21bd9cb024ca66f735bd756fcba78b8b2cc1ed 100644 (file)
@@ -1290,6 +1290,48 @@ CREATE TABLE IF NOT EXISTS `0_recurrent_invoices` (
 --
 
 
+--- Structure of table `0_reflines`
+
+DROP TABLE IF EXISTS `0_reflines`;
+
+CREATE TABLE `0_reflines` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `trans_type` int(11) NOT NULL,
+  `prefix` char(5) NOT NULL DEFAULT '',
+  `pattern` varchar(35) NOT NULL DEFAULT '1',
+  `description` varchar(60) NOT NULL DEFAULT '',
+  `default` tinyint(1) NOT NULL DEFAULT '0',
+  `inactive` tinyint(1) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `prefix` (`trans_type`, `prefix`)
+) ENGINE=InnoDB AUTO_INCREMENT=23;
+
+--- Data of table `0_reflines`
+
+INSERT INTO `0_reflines` VALUES
+('1', '0', '', '{001}/{YYYY}', '', '1', '0'),
+('2', '1', '', '{001}/{YYYY}', '', '1', '0'),
+('3', '2', '', '{001}/{YYYY}', '', '1', '0'),
+('4', '4', '', '{001}/{YYYY}', '', '1', '0'),
+('5', '10', '', '{001}/{YYYY}', '', '1', '0'),
+('6', '11', '', '{001}/{YYYY}', '', '1', '0'),
+('7', '12', '', '{001}/{YYYY}', '', '1', '0'),
+('8', '13', '', '{001}/{YYYY}', '', '1', '0'),
+('9', '16', '', '{001}/{YYYY}', '', '1', '0'),
+('10', '17', '', '{001}/{YYYY}', '', '1', '0'),
+('11', '18', '', '{001}/{YYYY}', '', '1', '0'),
+('12', '20', '', '{001}/{YYYY}', '', '1', '0'),
+('13', '21', '', '{001}/{YYYY}', '', '1', '0'),
+('14', '22', '', '{001}/{YYYY}', '', '1', '0'),
+('15', '25', '', '{001}/{YYYY}', '', '1', '0'),
+('16', '26', '', '{001}/{YYYY}', '', '1', '0'),
+('17', '28', '', '{001}/{YYYY}', '', '1', '0'),
+('18', '29', '', '{001}/{YYYY}', '', '1', '0'),
+('19', '30', '', '{001}/{YYYY}', '', '1', '0'),
+('20', '32', '', '{001}/{YYYY}', '', '1', '0'),
+('21', '35', '', '{001}/{YYYY}', '', '1', '0'),
+('22', '40', '', '{001}/{YYYY}', '', '1', '0');
+
 -- --------------------------------------------------------
 
 --
@@ -1852,47 +1894,6 @@ INSERT INTO `0_sys_prefs` VALUES('suppress_tax_rates','setup.company', 'tinyint'
 
 -- --------------------------------------------------------
 
---
--- Table structure for table `0_sys_types`
---
-
-DROP TABLE IF EXISTS `0_sys_types`;
-CREATE TABLE IF NOT EXISTS `0_sys_types` (
-  `type_id` smallint(6) NOT NULL default '0',
-  `type_no` int(11) NOT NULL default '1',
-  `next_reference` varchar(100) NOT NULL default '',
-  PRIMARY KEY  (`type_id`)
-) ENGINE=InnoDB;
-
---
--- Dumping data for table `0_sys_types`
---
-
-INSERT INTO `0_sys_types` VALUES(0, 17, '1');
-INSERT INTO `0_sys_types` VALUES(1, 7, '1');
-INSERT INTO `0_sys_types` VALUES(2, 4, '1');
-INSERT INTO `0_sys_types` VALUES(4, 3, '1');
-INSERT INTO `0_sys_types` VALUES(10, 16, '1');
-INSERT INTO `0_sys_types` VALUES(11, 2, '1');
-INSERT INTO `0_sys_types` VALUES(12, 6, '1');
-INSERT INTO `0_sys_types` VALUES(13, 1, '1');
-INSERT INTO `0_sys_types` VALUES(16, 2, '1');
-INSERT INTO `0_sys_types` VALUES(17, 2, '1');
-INSERT INTO `0_sys_types` VALUES(18, 1, '1');
-INSERT INTO `0_sys_types` VALUES(20, 6, '1');
-INSERT INTO `0_sys_types` VALUES(21, 1, '1');
-INSERT INTO `0_sys_types` VALUES(22, 3, '1');
-INSERT INTO `0_sys_types` VALUES(25, 1, '1');
-INSERT INTO `0_sys_types` VALUES(26, 1, '1');
-INSERT INTO `0_sys_types` VALUES(28, 1, '1');
-INSERT INTO `0_sys_types` VALUES(29, 1, '1');
-INSERT INTO `0_sys_types` VALUES(30, 0, '1');
-INSERT INTO `0_sys_types` VALUES(32, 0, '1');
-INSERT INTO `0_sys_types` VALUES(35, 1, '1');
-INSERT INTO `0_sys_types` VALUES(40, 1, '1');
-
--- --------------------------------------------------------
-
 --
 -- Table structure for table `0_tags`
 --