<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[FrontAccounting forum — Closing and Opening Fiscal Years - Speedup]]></title>
		<link>https://frontaccounting.com/punbb/viewtopic.php?id=6360</link>
		<atom:link href="https://frontaccounting.com/punbb/extern.php?action=feed&amp;tid=6360&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[The most recent posts in Closing and Opening Fiscal Years - Speedup.]]></description>
		<lastBuildDate>Mon, 18 Jul 2016 05:53:45 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: Closing and Opening Fiscal Years - Speedup]]></title>
			<link>https://frontaccounting.com/punbb/viewtopic.php?pid=25819#p25819</link>
			<description><![CDATA[<p>The final version of functions <strong>close_transactions()</strong> and <strong>open_transactions</strong> in the file <strong>includes/db/audit_trail_db.inc</strong> that works even for large datasets has been <a href="https://github.com/apmuthu/frontaccounting/commit/c111c488b10fb991e80f0271a3c142b8896d4fe4">committed to my GitHub repo</a>. It is now an entirely MySQL affair and no updation by cycling through redundant <strong>id</strong> instances of the <strong>audit_trail</strong> table and is as follows:<br /></p><div class="codebox"><pre><code>/*
    Confirm and close for edition all transactions up to date $todate, 
    and reindex    journal.
*/
function close_transactions($todate) {
    $errors = 0;

    begin_transaction();

    $sql = &quot;DROP TABLE IF EXISTS &quot;.TB_PREF.&quot;audit_tmp&quot;;
    db_query($sql, &quot;Cannot drop hold table if present&quot;);

    $sql2 = &quot;CREATE TABLE &quot;.TB_PREF.&quot;audit_tmp SELECT id, Counter AS gl_seq FROM 
        ( SELECT id, gl_date, fiscal_year
            , (@counter:=IF(fiscal_year &lt;&gt; @lastyr, 1, @counter+1)) AS Counter
            , (@lastyr:=IF(fiscal_year &lt;&gt; @lastyr, fiscal_year, @lastyr)) AS LastYr FROM
            ( SELECT DISTINCT a.id, a.gl_date, a.fiscal_year 
                FROM &quot;.TB_PREF.&quot;gl_trans gl INNER JOIN &quot;.TB_PREF.&quot;audit_trail a 
                  ON (gl.type=a.type AND gl.type_no=a.trans_no) 
                WHERE gl_date&lt;=&#039;&quot;. date2sql($todate) .&quot;&#039; AND NOT ISNULL(gl_seq) 
                ORDER BY a.fiscal_year, a.gl_date, a.id) b, (SELECT (@lastyr:=0), (@counter:=1)
            ) w
        ) c&quot;;
    db_query($sql2, &quot;Cannot create hold table for gl_seq sequential values&quot;);

    $sql3 = &quot;UPDATE &quot;.TB_PREF.&quot;audit_tmp a LEFT JOIN &quot;.TB_PREF.&quot;audit_trail b USING (id) 
            SET b.gl_seq=a.gl_seq&quot;;
    $result = db_query($sql3, &quot;Cannot update audit_trail.gl_seq from hold table&quot;);

    db_query($sql, &quot;Cannot drop hold table&quot;);

    commit_transaction();
}

/*
    Reopen all transactions for edition up from date $fromdate
*/
function open_transactions($fromdate) {

    $sql = &quot;UPDATE &quot;.TB_PREF.&quot;audit_trail SET gl_seq=0 
        WHERE gl_date&gt;=&#039;&quot;. date2sql($fromdate) .&quot;&#039; 
        AND !ISNULL(gl_seq) AND !ISNULL(fiscal_year)&quot;;

    $result = db_query($sql, &quot;Cannot open transactions&quot;);
}</code></pre></div><p>The <strong>Audit Trail relationships</strong> section of <a href="https://frontaccounting.com/fawiki/index.php?n=Devel.ERDiagram23">Wiki</a> has been updated.</p><p>An example of the Opening / Closing entries in the <strong>gl_trans</strong> table is attached. The sql to extract it is:<br /></p><div class="codebox"><pre><code>$sql = &quot;SELECT * FROM &quot;.TB_PREF&quot;.gl_trans WHERE `type`=0 AND memo_ IN (&quot;._(&#039;Open Balance&#039;).&quot;, &quot;._(&#039;Closing Year&#039;).&quot;)&quot;;</code></pre></div><p>or in plain sql with no translation and no table prefix:<br /></p><div class="codebox"><pre><code>SELECT * FROM gl_trans WHERE `type`=0 AND memo_ IN (&#039;Open Balance&#039;, &#039;Closing Year&#039;);</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (apmuthu)]]></author>
			<pubDate>Mon, 18 Jul 2016 05:53:45 +0000</pubDate>
			<guid>https://frontaccounting.com/punbb/viewtopic.php?pid=25819#p25819</guid>
		</item>
		<item>
			<title><![CDATA[Re: Closing and Opening Fiscal Years - Speedup]]></title>
			<link>https://frontaccounting.com/punbb/viewtopic.php?pid=25806#p25806</link>
			<description><![CDATA[<p>For a start, if you have a large amount of transactions in each year you wish to close/open,&nbsp; the <strong>function open_transactions</strong> can be replaced with:<br /></p><div class="codebox"><pre><code>function open_transactions($fromdate) {

    $sql = &quot;UPDATE &quot;.TB_PREF.&quot;audit_trail SET gl_seq=0 WHERE gl_date&gt;=&#039;&quot;. date2sql($fromdate) .&quot;&#039; AND !ISNULL(gl_seq) AND !ISNULL(fiscal_year)&quot;;
    db_query($sql, &quot;Cannot open transactions&quot;);

}</code></pre></div><p>The above has been committed in my GitHub Repo - <a href="https://github.com/apmuthu/frontaccounting/commit/1fcac2caa2e649e1aeb72b2c0f36226ab98531b4">1</a>, <a href="https://github.com/apmuthu/frontaccounting/commit/8259ae4416620826c74265e4b36d4259fe3ca16c">2</a>.</p><p>The <strong>function close_transactions</strong> called in <strong>function close_year</strong> in <strong>admin/db/fiscalyears_db.inc</strong> be commented out and it&#039;s functionality be manually executed from the sql obtained from:<br /></p><div class="codebox"><pre><code>$sql = &quot;
DROP TABLE IF EXISTS &quot;.TB_PREF.&quot;audit_tmp;
CREATE TEMPORARY TABLE &quot;.TB_PREF.&quot;audit_tmp SELECT id, Counter AS gl_seq FROM (
SELECT id, gl_date, fiscal_year
    , (@counter:=IF(fiscal_year &lt;&gt; @lastyr, 1, @counter+1)) AS Counter
    , (@lastyr:=IF(fiscal_year &lt;&gt; @lastyr, fiscal_year, @lastyr)) AS LastYr FROM
( SELECT DISTINCT a.id, a.gl_date, a.fiscal_year 
FROM &quot;.TB_PREF.&quot;gl_trans gl INNER JOIN &quot;.TB_PREF.&quot;audit_trail a ON (gl.type=a.type AND gl.type_no=a.trans_no) 
WHERE gl_date&lt;=&#039;&quot;. date2sql($todate) .&quot;&#039; AND NOT ISNULL(gl_seq) 
ORDER BY a.fiscal_year, a.gl_date, a.id) b, (SELECT (@lastyr:=0), (@counter:=1)) w
) c;
UPDATE &quot;.TB_PREF.&quot;audit_tmp a LEFT JOIN &quot;.TB_PREF.&quot;audit_trail b USING (id) SET b.gl_seq=a.gl_seq;
DROP TABLE &quot;.TB_PREF.&quot;audit_tmp;
&quot;;</code></pre></div><p>We also need to see if there is any performance gain by indexing <strong>gl_seq</strong> in the <strong>audit_trail</strong> table.</p><p>Only closed fiscal years will have the <strong>audit_table.gl_seq</strong> chronologically sequentially numbered (some will be NULL and some others 0 as well). All open fiscal years will have the said field as 0 or NULL only.</p><p>At the end of successful closure of a fiscal year, on it&#039;s last date as the last 2 <strong>gl_trans.counter</strong> entries we get the memo_ field set to <strong>Closing Year</strong> with the <strong>amount</strong> values in contra. When the fiscal year is then re-opened, these entries still remain and will <em>need to be manually deleted</em> to be re-created when it is subsequently closed.</p><p>The <a href="https://frontaccounting.com/fawiki/index.php?n=Devel.ERDiagram23">Audit Trail ERD</a> is available in the Wiki.</p>]]></description>
			<author><![CDATA[null@example.com (apmuthu)]]></author>
			<pubDate>Sat, 16 Jul 2016 13:26:58 +0000</pubDate>
			<guid>https://frontaccounting.com/punbb/viewtopic.php?pid=25806#p25806</guid>
		</item>
		<item>
			<title><![CDATA[Re: Closing and Opening Fiscal Years - Speedup]]></title>
			<link>https://frontaccounting.com/punbb/viewtopic.php?pid=25805#p25805</link>
			<description><![CDATA[<p>Even if we mimic the <a href="http://php.net/manual/en/mysqli.multi-query.php">mysqli_multi_query</a> in the mysql driver used in FA 2.3.x, it is still very slow when the <a href="http://www.bitrepository.com/mysql-multi-query-function-an-alternative-to-mysqlis-multi_query.html">equivalent function</a> below is used:<br /></p><div class="codebox"><pre><code>function multiQuery($queryBlock, $delimiter = &#039;;&#039;) {
    $inString = false;
    $escChar = false;
    $sql = &#039;&#039;;
    $stringChar = &#039;&#039;;
    $queryLine = array();
    $sqlRows = explode ( &quot;\n&quot;, $queryBlock );
    $delimiterLen = strlen ( $delimiter );
    do {
        $sqlRow = current ( $sqlRows ) . &quot;\n&quot;;
        $sqlRowLen = strlen ( $sqlRow );
        for ( $i = 0; $i &lt; $sqlRowLen; $i   ) {
            if ( ( substr ( ltrim ( $sqlRow ), $i, 2 ) === &#039;--&#039; || substr ( ltrim ( $sqlRow ), $i, 1 ) === &#039;#&#039; ) &amp;&amp; !$inString ) {
                break;
            }
            $znak = substr ( $sqlRow, $i, 1 );
            if ( $znak === &#039;\&#039;&#039; || $znak === &#039;&quot;&#039; ) {
                if ( $inString ) {
                    if ( !$escChar &amp;&amp; $znak === $stringChar ) {
                        $inString = false;
                    }
                }
                else {
                    $stringChar = $znak;
                    $inString = true;
                }
            }
            if ( $znak === &#039;\\&#039; &amp;&amp; substr ( $sqlRow, $i - 1, 2 ) !== &#039;\\\\&#039; ) {
                $escChar = !$escChar;
            }
            else {
                $escChar = false;
            }
            if ( substr ( $sqlRow, $i, $delimiterLen ) === $delimiter ) {
                if ( !$inString ) {
                    $sql = trim ( $sql );
                    $delimiterMatch = array();
                    if ( preg_match ( &#039;/^DELIMITER[[:space:]]*([^[:space:]] )$/i&#039;, $sql, $delimiterMatch ) ) {
                        $delimiter = $delimiterMatch [1];
                        $delimiterLen = strlen ( $delimiter );
                    }
                    else {
                        $queryLine [] = $sql;
                    }
                    $sql = &#039;&#039;;
                    continue;
                }
            }
            $sql .= $znak;
        }
    } while ( next( $sqlRows ) !== false );
 
    return $queryLine;
}</code></pre></div><p>It&#039;s usage will be:<br /></p><div class="codebox"><pre><code>$multiple_queries = &#039;SELECT CURRENT_USER();
SELECT Name FROM City ORDER BY ID LIMIT 20, 5;&#039;;
 
$sql_queries = multiQuery($multiple_queries);
 
foreach($sql_queries as $sql_query) {
    // Execute each query
    mysql_query($sql_query) or exit(&#039;SQL: &#039;.$sql_query.&#039;, Error: &#039;.mysql_error());
}</code></pre></div><p><a href="http://www.w3schools.com/PHP/func_mysqli_multi_query.asp">Tutorial on MySQLi multi query function</a></p>]]></description>
			<author><![CDATA[null@example.com (apmuthu)]]></author>
			<pubDate>Sat, 16 Jul 2016 13:19:24 +0000</pubDate>
			<guid>https://frontaccounting.com/punbb/viewtopic.php?pid=25805#p25805</guid>
		</item>
		<item>
			<title><![CDATA[Closing and Opening Fiscal Years - Speedup]]></title>
			<link>https://frontaccounting.com/punbb/viewtopic.php?pid=25804#p25804</link>
			<description><![CDATA[<p>The file <strong>includes/db/audit_trail_db.inc</strong> has the functions <strong>close_transactions()</strong> and <strong>open_transactions()</strong> and in both, only the <strong>audit_trail.gl_seq</strong> field is updated and the <strong>gl_trans.gl_date</strong> field is unnecessarily being called in for ordering whereas the <strong>audit_trail.gl_date</strong> already has the info taken from the former at the time of transaction creation.</p><p>In the <strong>function open_transactions()</strong> there is no need for any ordering as a mere set to 0 of the <strong>gl_seq</strong> field is all that is done wholesale.</p><p>In the <strong>close_transactions()</strong>, the LEFT JOIN should be an INNER JOIN as there is no point in attempting to update records in <strong>audit_trail</strong> table where no <strong>id</strong> exists if it only existed in the <strong>gl_trans</strong> table!</p><p>A pure MySQL implementation of the <strong>close_transactions</strong> sql would reduce to:<br /></p><div class="codebox"><pre><code>SET @lastyr:=0;
SET @counter:=1;
CREATE TEMPORARY TABLE audit_tmp SELECT id, Counter AS gl_seq FROM (
SELECT id, gl_date, fiscal_year
    , (@counter:=IF(fiscal_year &lt;&gt; @lastyr, 1, @counter+1)) AS Counter
    , (@lastyr:=IF(fiscal_year &lt;&gt; @lastyr, fiscal_year, @lastyr)) AS LastYr FROM
( SELECT DISTINCT a.id, a.gl_date, a.fiscal_year 
FROM gl_trans gl INNER JOIN audit_trail a ON (gl.type=a.type AND gl.type_no=a.trans_no) 
WHERE gl_date&lt;=&#039;2015-12-31&#039; AND NOT ISNULL(gl_seq) 
ORDER BY a.fiscal_year, a.gl_date, a.id) b
) c;
UPDATE audit_tmp a LEFT JOIN audit_trail b USING (id) SET b.gl_seq=a.gl_seq;
DROP TABLE audit_tmp;</code></pre></div><p>Likewise, the <strong>open_transactions</strong> sql would reduce to:<br /></p><div class="codebox"><pre><code>UPDATE audit_trail SET gl_seq=0 WHERE gl_date&gt;=&#039;2016-01-01&#039; AND !ISNULL(gl_seq);</code></pre></div><p>Failure to correct this will cause a timeout when trying to close large fiscal years.</p>]]></description>
			<author><![CDATA[null@example.com (apmuthu)]]></author>
			<pubDate>Sat, 16 Jul 2016 11:40:06 +0000</pubDate>
			<guid>https://frontaccounting.com/punbb/viewtopic.php?pid=25804#p25804</guid>
		</item>
	</channel>
</rss>
