+//--------------------------------------------------------------------------------------
+//
+// Expands selected quick entry $id into GL posings and adds to cart.
+// returns calculated amount posted to bank GL account.
+//
+function display_quick_entries(&$cart, $id, $base, $type, $descr='')
+{
+ $bank_amount = 0;
+
+ if (!isset($id) || $id == null || $id == "")
+ {
+ display_error( _("No Quick Entries are defined."));
+ set_focus('totamount');
+ }
+ else
+ {
+ if ($type == QE_DEPOSIT)
+ $base = -$base;
+ if ($type != QE_SUPPINV && $type != QE_JOURNAL) // only one quick entry on journal/bank transaction
+ $cart->clear_items();
+
+ // as for now tax_group is passed only in QE_SUPPINV
+ $qe_lines = quickentry_calculate($base, $id, @$cart->tax_group_id, $cart->tran_date);
+
+ if ($qe_lines === 0)
+ {
+ display_error( _("No Quick Entry lines are defined."));
+ set_focus('totamount');
+ return 0;
+ } elseif ($qe_lines === -1)
+ {
+ display_error(_("Cannot post to GL account used by more than one tax type."));
+ return 0;
+ }
+ foreach($qe_lines as $qe_line)
+ {
+ if ($descr != '') $qe_line['descr'] .= ': '.$descr;
+ if ($type != QE_SUPPINV)
+ $cart->add_gl_item($qe_line['code'], $qe_line['dim1'],
+ $qe_line['dim2'], $qe_line['amount'], $qe_line['descr']);
+ else
+ {
+ $acc_name = get_gl_account_name($qe_line['code']);
+ $cart->add_gl_codes_to_trans($qe_line['code'],
+ $acc_name, $qe_line['dim1'],
+ $qe_line['dim2'], $qe_line['amount'], $qe_line['descr']);
+ }
+ }
+ }
+ return $bank_amount;
+}
+
+//--------------------------------------------------------------------------------------
+
+function quickentry_calculate($base, $id, $taxgroup=null, $date=null)
+{
+ $gl_entries = array();
+ $qe = get_quick_entry($id);
+ $type = $qe['type'];
+ $total = $base;
+ // quick entry made on account balance is special case.
+ if ($qe['bal_type'] == 1) // if this is quick entry based on balance - calculate it
+ {
+ // Note, that this is ugly hack overriding standard field usage
+ // just to make the feature available between major FA releases!
+ $gl_code = $qe['base_desc'];
+ $monthly = $qe['base_amount'] == 1.0;
+
+ if (!isset($date))
+ $date = Today();
+
+ if ($monthly) // marked as monthly
+ $begin = begin_month($date);
+ else
+ {
+ if (is_account_balancesheet($gl_code)) // total
+ $begin = "";
+ else
+ $begin = begin_fiscalyear(); // from fiscalyear begin
+ }
+ $base = get_gl_trans_from_to($begin, $date, $gl_code);
+
+ }
+
+ $result = get_quick_entry_lines($id);
+ if (db_num_rows($result) == 0)
+ {
+ return 0;
+ }
+
+ // first calculate total rate in case more than one tax is used
+ $totrate = 0;
+ while ($row = db_fetch($result))
+ {
+ $qe_lines[] = $row;
+
+ switch (strtolower($row['action'])) {
+ case "t": // post taxes calculated on base amount
+ case "t+": // ditto & increase base amount
+ case "t-": // ditto & reduce base amount
+ if (substr($row['action'], 0, 1) != 'T')
+ $totrate += get_tax_type_default_rate($row['dest_id']);
+ }
+ }
+ $first = true;
+ $taxbase = 0;
+ foreach($qe_lines as $qe_line)
+ {
+ $gl_code = $qe_line['dest_id'];
+ switch (strtolower($qe_line['action'])) {
+ case "=": // post current base amount to GL account
+ $part = $base;
+ break;
+ case "a": // post amount to GL account and reduce base
+ $part = $qe_line['amount'];
+ break;
+ case "a+": // post amount to GL account and increase base
+ $part = $qe_line['amount']; $base += $part;
+ break;
+ case "a-": // post amount to GL account and reduce base
+ $part = $qe_line['amount']; $base -= $part;
+ break;
+ case "%": // store acc*amount% to GL account
+ $part = round2($base * $qe_line['amount'] / 100, user_price_dec());
+ break;
+ case "%+": // ditto & increase base amount
+ $part = round2($base * $qe_line['amount'] / 100, user_price_dec());
+ $base += $part;
+ break;
+ case "%-": // ditto & reduce base amount
+ $part = round2($base * $qe_line['amount'] / 100, user_price_dec());
+ $base -= $part;
+ break;
+ case "t": // post taxes calculated on base amount
+ case "t+": // ditto & increase base amount
+ case "t-": // ditto & reduce base amount
+ if ($first)
+ {
+ $taxbase = $base/($totrate+100);
+ $first = false;
+ }
+
+ if (substr($qe_line['action'],0,1) != 'T')
+ $part = $taxbase;
+ else
+ $part = $base/100;
+
+ $item_tax = get_tax_type($qe_line['dest_id']);
+ //if ($type == QE_SUPPINV && substr($qe_line['action'],0,1) != 'T')
+ if ($type == QE_SUPPINV)
+ {
+ $rates = 0;
+ $res = get_tax_group_rates($taxgroup);
+ while ($row = db_fetch($res))
+ $rates += $row['rate'];
+ if ($rates == 0)
+ continue 2;
+ }
+ $tax = round2($part * $item_tax['rate'], user_price_dec());
+ if ($tax == 0) continue 2;
+ $gl_code = ($type == QE_DEPOSIT || ($type == QE_JOURNAL && $base < 0))
+ ? $item_tax['sales_gl_code'] : $item_tax['purchasing_gl_code'];
+ if (!is_tax_gl_unique($gl_code)) {
+ return -1; // more than one taxtype used with this GL account
+ }
+
+ $part = $tax;
+ if (strpos($qe_line['action'], '+'))
+ $base += $tax;
+ elseif (strpos($qe_line['action'], '-'))
+ $base -= $tax;
+ }
+ $gl_entries[] = array(
+ 'code' => $gl_code,
+ 'name' => get_gl_account_name($gl_code),
+ 'dim1' => $qe_line['dimension_id'],
+ 'dim2' => $qe_line['dimension2_id'],
+ 'amount' => $part,
+ 'descr' => $qe_line['memo']
+ );
+ }
+ return $gl_entries;
+}
+
+
+//--------------------------------------------------------------------------------------
+//
+// Simple English version of number to words conversion.
+//
+function _number_to_words($number)
+{
+ $Bn = floor($number / 1000000000); /* Billions (giga) */
+ $number -= $Bn * 1000000000;
+ $Gn = floor($number / 1000000); /* Millions (mega) */
+ $number -= $Gn * 1000000;
+ $kn = floor($number / 1000); /* Thousands (kilo) */
+ $number -= $kn * 1000;
+ $Hn = floor($number / 100); /* Hundreds (hecto) */
+ $number -= $Hn * 100;
+ $Dn = floor($number / 10); /* Tens (deca) */
+ $n = $number % 10; /* Ones */
+
+ $res = "";
+
+ if ($Bn)
+ $res .= _number_to_words($Bn) . " Billion";
+ if ($Gn)
+ $res .= (empty($res) ? "" : " ") . _number_to_words($Gn) . " Million";
+ if ($kn)
+ $res .= (empty($res) ? "" : " ") . _number_to_words($kn) . " Thousand";
+ if ($Hn)
+ $res .= (empty($res) ? "" : " ") . _number_to_words($Hn) . " Hundred";
+
+ $ones = array("", "One", "Two", "Three", "Four", "Five", "Six",
+ "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
+ "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen",
+ "Nineteen");
+ $tens = array("", "", "Twenty", "Thirty", "Fourty", "Fifty", "Sixty",
+ "Seventy", "Eighty", "Ninety");
+
+ if ($Dn || $n)
+ {
+ if (!empty($res))
+ $res .= " and ";
+ if ($Dn < 2)
+ $res .= $ones[$Dn * 10 + $n];
+ else
+ {
+ $res .= $tens[$Dn];
+ if ($n)
+ $res .= "-" . $ones[$n];
+ }
+ }
+
+ if (empty($res))
+ $res = "zero";
+ return $res;
+}
+
+function price_in_words($amount, $document=0)
+{
+ // use local price_in_words() if the hook is defined
+ $price = hook_price_in_words($amount, $document);
+ if ($price)
+ return $price;
+
+ // Only usefor Remittance and Receipts as default
+ if (!($document == ST_SUPPAYMENT || $document == ST_CUSTPAYMENT || $document == ST_CHEQUE))
+ return "";
+ if ($amount < 0 || $amount > 999999999999)
+ return "";
+ $dec = user_price_dec();
+ if ($dec > 0)
+ {
+ $divisor = pow(10, $dec);
+ $frac = round2($amount - floor($amount), $dec) * $divisor;
+ $frac = sprintf("%0{$dec}d", round2($frac, 0));
+ $and = _("and");
+ $frac = " $and $frac/$divisor";
+ }
+ else
+ $frac = "";
+ return _number_to_words(intval($amount)) . $frac;
+}
+