Hi,

I really, really needed a report that gave me a month-by-month cash flow 
(profit and loss) summary for the past two years. And given that I can 
do it much quicker in PHP and have a Drupal instance set up that already 
talks to my LSMB database, I implemented it there.

The core SQL I took out of pnl__income_statement_cash , stripping out 
the business unit and year-end options. Mainly just added a field 
populated with date_trunc. I'm sure this could be added back to the 
stored function with a new parameter.

In any case, here's the code I wrote. Not pretty, but got the job done 
for me pretty quickly... Would be great to get something like this in LSMB.

I would think the first thing would be to modify 
pnl__income_statement_cash and pnl__income_statement_accrual with one 
more parameter, to specify a grouping period. Maybe some other reports, 
too...


/**
  * Helper function to get report data from LSMB 14
  *
  * @param string $dtstart Start date range
  * @param string $dtend End of date range
  * @param string $groupperiod One of null, 'week', 'month', 'quarter', 
'year'
  *
  * @return object with many attached arrays. Following keys are set:
  *   -> cols Array of columns. Each column is an object containing:
  *     -> key used in data array
  *     -> label
  *     -> expense total for this column
  *     -> income total for this column
  *     -> total income - expense for this column
  *   -> rows Array of rows. Each row is an object containing:
  *     -> key used in data array
  *     -> label -- name of account
  *     -> link -- link to use for account
  *     -> accno -- Account Number
  *     -> category -- I or E
  *     -> expense -- total for this row
  *     -> income -- total for this row
  *   -> total income - expense for all rows/columns
  *   -> data array of arrays. Outer array = row, inner array = column
  */
function auriga_dashboard_pnl_cash($dtstart= NULL, $dtend = NULL, 
$groupperiod = NULL) {
   $params = array();
   $query = "SELECT a.id, a.accno, a.description, a.category, ah.id as 
header_id, ah.accno as header_ac
cno,
     ah.description as header_description, ";
   if ($groupperiod) {
     $query .= "date_trunc(:groupperiod, ac.transdate) AS transperiod, ";
     $params[':groupperiod'] = $groupperiod;
   }
   $query .= " CASE WHEN a.category = 'E' THEN -1 ELSE 1 END * 
sum(ac.amount) AS amount,
           at.path
      FROM account a
      JOIN account_heading ah on a.heading = ah.id
      JOIN acc_trans ac ON a.id = ac.chart_id AND ac.approved
      JOIN tx_report gl ON ac.trans_id = gl.id AND gl.approved
      JOIN account_heading_tree at ON a.heading = at.id
      WHERE ac.approved is true ";
   if ($dtstart) {
     $query .= " AND (ac.transdate >= :dtstart) ";
     $params[':dtstart'] = $dtstart;
   }
   if ($dtend) {
     $query .= " AND (ac.transdate <= :dtend) ";
     $params[':dtend'] = $dtend;
   }
   $query .= "  AND a.category IN ('I', 'E')
     GROUP BY a.id, a.accno, ";
   if ($groupperiod) {
     $query .= "transperiod, ";
   }
   $query .= " a.description, a.category,
           ah.id, ah.accno, ah.description, at.path
           ORDER BY a.category DESC, a.accno ASC ";
   if ($groupperiod) {
     $query .= ", transperiod";
   }
   db_set_active('lsmb14');
   $result = db_query($query, $params);
   $items = $result->fetchAll();
   db_set_active();

   // now let's build our arrays...
   $cols = array();
   $rows = array();
   $data = array();
   $total = 0;
   foreach ($items as $item) {
     $type = $item->category == 'I' ? 'income' : 'expense';
     if (empty($rows[$item->accno])) {
       $rows[$item->accno] = array(
         'key' => $item->accno,
         'label' => $item->description,
         'accno' => $item->accno,
         'link' => $item->path,
         'category' => $item->category,
         'expense' => 0,
         'income' => 0,
       );
     }
     $rows[$item->accno][$type] += $item->amount;

     $perioddate = strtotime($item->transperiod);
     switch ($groupperiod) {
     case 'week':
       $period = date('Y',$perioddate).' Week '.date('W', $perioddate);
       break;
     case 'month':
       $period = date('M',$perioddate).' '.date('Y', $perioddate);
       break;
     case 'year':
       $period = date('Y',$perioddate);
       break;
     case 'quarter':
       $period = date('Y',$perioddate).' Q' .ceil(date('m', $perioddate)/3);
       break;
     default:
       $period = $dtstart . ' - ' . $dtend;
     }

     if (empty($cols[$item->transperiod])) {
       $cols[$item->transperiod] = array(
         'key' => $item->transperiod,
         'label' => $period,
         'expense' => 0,
         'income' => 0,
         'total' => 0,
       );
     }
     $cols[$item->transperiod][$type] += $item->amount;

     $data[$item->accno][$item->transperiod] = $item->amount;

   }
   // Now calculate column totals...
   foreach ($cols as $k=>$col) {
     $cols[$k]['total'] = $col['income'] - $col['expense'];
     $total += $cols[$k]['total'];
   }
   $ret = new stdClass();
   $ret->rows = $rows;
   $ret->cols = $cols;
   $ret->total = $total;
   $ret->data = $data;

   // TODO: Move the following to a theme function, and return $ret
   $out = '<h2>Profit and Loss, cash basis</h2>';
   $out .= '<h3>'.$dtstart.' - '.$dtend.'</h3>';

   $out .= '<table class="timereport">';
     $out .= '<thead>';
       $out .= '<tr>';
         $out .= '<th>Account #</th><th>Description</th>';
   foreach ($ret->cols as $col) {
     $out .= '<th>'.$col['label'].'</th>';
   }
   if (count($ret->cols) > 1) {
     $out .= '<th>Total</th>';
   }
       $out .= '</tr>';
     $out .= '</thead>';
     $out .= '<tbody>';
     // flag to get an income subtotal
     $in_income = true;
     foreach ($ret->rows as $r=>$row) {
       if ($in_income && $row['category'] == 'E') {
         // we are no longer in income, do a subtotal row
         $in_income = false;
         $out .= '<tr><th></th><th>Subtotal of Income:</th>';
         foreach ($ret->cols as $k=>$col) {
           $out .= '<th>' . $col['income'] . '</th>';
        }
         $out .= '</tr>';
       }
       $out .= '<tr><td>' . $row['accno'] . '</td><td>'. 
$row['label'].'</td>';
       foreach ($ret->cols as $k=>$col) {
         $out .= '<td>';
         $out .= isset($ret->data[$r][$k]) ? $ret->data[$r][$k] : 0;
         $out .= '</td>';
       }
       $out .= '</tr>';
     }
         $out .= '<tr><th></th><th>Subtotal of Expenses:</th>';
         foreach ($ret->cols as $k=>$col) {
           $out .= '<th>' . $col['expense'] . '</th>';
         }
         $out .= '</tr>';
         $out .= '<tr><th></th><th>Totals, income less expenses:</th>';
         foreach ($ret->cols as $k=>$col) {
           $out .= '<th>' . $col['total'] . '</th>';
         }
         $out .= '</tr>';



     $out .= '</tbody>';
   $out .= '</table>';

   return $out;
}



Cheers,
John Locke
http://www.freelock.com

------------------------------------------------------------------------------
CenturyLink Cloud: The Leader in Enterprise Cloud Services.
Learn Why More Businesses Are Choosing CenturyLink Cloud For
Critical Workloads, Development Environments & Everything In Between.
Get a Quote or Start a Free Trial Today. 
http://pubads.g.doubleclick.net/gampad/clk?id=119420431&iu=/4140/ostg.clktrk
_______________________________________________
Ledger-smb-devel mailing list
Ledger-smb-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ledger-smb-devel

Reply via email to