function set_global_connection()
{
- global $db;
+ global $db, $transaction_level;
+
+ cancel_transaction(); // cancel all aborted transactions if any
+ $transaction_level = 0;
$db = $_SESSION["wa_current_user"]->get_db_connection();
}
//
// General database functions common for all modules.
//
-//-------------------------------------------------------------------
+//-------------------------------------------------------------------
+// Multilevel transaction control.
+//
+
function begin_transaction()
{
- db_query("BEGIN", "could not start a transaction");
+ global $transaction_level; // set in set_global_connection()
+
+ if (!$transaction_level) {
+ error_log('begin');
+ db_query("BEGIN", "could not start a transaction");
+ }
+ $transaction_level++;
+ error_log("level:$transaction_level");
}
function commit_transaction()
{
- db_query("COMMIT", "could not commit a transaction");
+ global $transaction_level;
+
+ $transaction_level--;
+
+ if (!$transaction_level) {
+ error_log('commit');
+ db_query("COMMIT", "could not commit a transaction");
+ }
+ error_log("level:$transaction_level");
}
+/*
+ This function is called on end of script execution to cancel
+ all aborted transactions (if any)
+*/
function cancel_transaction()
{
- db_query("ROLLBACK", "could not cancel a transaction");
+ global $transaction_level;
+
+ if ($transaction_level) {
+ error_log('rollback');
+ db_query("ROLLBACK", "could not cancel a transaction");
+ } else
+ error_log("no transactions");
+
}
+
//-----------------------------------------------------------------------------
// Update record activity status.
//
/*
Helper to avoid sparse log notices.
*/
-function end_flush () {
- global $Ajax;
+function end_flush() {
+ global $Ajax, $transaction_level;
if (isset($Ajax))
$Ajax->run();
// flush all output buffers (works also with exit inside any div levels)
while(ob_get_level()) ob_end_flush();
+
+ // if any transaction was aborted unexpectedly rollback changes
+ cancel_transaction();
}
function display_db_error($msg, $sql_statement=null, $exit=true)
// Makes parent documents for direct delivery/invoice by recurent call.
// $policy - 0 or 1: writeoff/return for IV, back order/cancel for DN
function write($policy=0) {
+ begin_transaction(); // prevents partial database changes in case of direct delivery/invoice
if (count($this->src_docs) == 0 && ($this->trans_type == ST_SALESINVOICE || $this->trans_type == ST_CUSTDELIVERY)) {
// this is direct document - first add parent
$src = (PHP_VERSION<5) ? $this : clone( $this ); // make local copy of this cart
}
switch($this->trans_type) {
case ST_SALESINVOICE:
- return write_sales_invoice($this);
+ write_sales_invoice($this); break;
case ST_CUSTCREDIT:
- return write_credit_note($this, $policy);
+ write_credit_note($this, $policy); break;
case ST_CUSTDELIVERY:
- return write_sales_delivery($this, $policy);
+ write_sales_delivery($this, $policy); break;
case ST_SALESORDER:
case ST_SALESQUOTE:
if ($this->trans_no==0) // new document
- return add_sales_order($this);
+ add_sales_order($this);
else
- return update_sales_order($this);
+ update_sales_order($this);
}
+
+ commit_transaction();
}
function set_customer($customer_id, $customer_name, $currency, $discount, $payment, $cdiscount=0)