226

(5 replies, posted in Accounts Receivable)

Set the payment terms to net xx.  To create, Setup->Payment Terms.

227

(10 replies, posted in Report Bugs here)

I've changed (fixed) these search functions in my fork so that clicking the boxes do not change how the drop down lists work, but just adds the ability to search by keyword.   I also have an autocomplete feature so that the search matches are displayed after each key is typed.  And I have also enabled the enter key universally, which is often (perhaps always?) discarded in FA.  So the following advice I have might not work in vanilla FA.

But try this:

1. Comment out the following code in ui_lists.php:

/*
            if ($txt == '') {
                if ($spec_option === false && $selected_id == array())
                    $limit = ' LIMIT 1';
                else
                    $opts['where'][] = $valfield . "=". db_escape(get_post($name, $spec_id));
            }
            else
*/

Then your drop down lists should still work with the boxes checked.

2. After typing in the search box, try the tab key, which allows ajax to update the page.   The matched search items would then appear in the drop down list.   I believe vanilla FA matches on item number, not description.

3.  For the customer/supplier lists, type a space key in the drop down list to display the search box.  Enter the search text and tab should allow ajax to update the page

228

(4 replies, posted in Banking and General Ledger)

Try:

core/gl/gl_journal.php:

function subledger_list($name, $account, $selected_id=null)
                'type' => (@$SysPrefs->search_autocomplete ? 4 : 1),
                'size' => 20,
                'async' => false,
+        'spec_option' => 'Nada'
        ) );

core/gl/gl_journal.php:

function check_item_data()
                set_focus('code_id');
                return false;
        }
+/*
        if (is_subledger_account(get_post('code_id'))) {
                if(!get_post('person_id')) {
                        display_error(_("You must select subledger account."));
                       $Ajax->activate('items_table');
                       set_focus('person_id');
                        return false;
                }
        }
+*/

229

(4 replies, posted in Banking and General Ledger)

If the bank account is listed in a supplier as an accounts payable account or in a customer as an accounts receivable account, the counterparty field shows up.   So if you do not want the counterparty field, then find the supplier/customer and change it to go to a different account.  (Use Accounts Payable or Accounts Receivable).

1.  By design, the Bank GL Inquiry report is cluttered with GL entries.   If you do not want the GL entries, then use the built-in Bank Inquiry report.  Indeed, I don't use the GL report personally, but was requested by accounting staff.

2. The report relies on additional core change to gl_bank.php for this function to work.  It might work if you add something like

if isset($_GET['bank_account'])
    $_POST['bank_account'] = $_GET['bank_account'];

 
All the core changes to that file are:

diff --git a/core/gl/gl_bank.php b/core/gl/gl_bank.php
index 71e2c04..0897a1b 100644
--- a/core/gl/gl_bank.php
+++ b/core/gl/gl_bank.php
@@ -30,6 +30,8 @@ if ($SysPrefs->use_popup_windows)
 if (user_use_date_picker())
     $js .= get_js_date_picker();
 
+set_posts(array("bank_account"));
+
 if (isset($_GET['NewPayment'])) {
     $_SESSION['page_title'] = _($help_context = "Bank Account Payment Entry");
     create_cart(ST_BANKPAYMENT, 0);
@@ -43,6 +45,15 @@ if (isset($_GET['NewPayment'])) {
     $_SESSION['page_title'] = _($help_context = "Modify Bank Deposit Entry")." #".$_GET['trans_no'];
     create_cart(ST_BANKDEPOSIT, $_GET['trans_no']);
 }
+
+if (isset($_SERVER['HTTP_REFERER'])) {
+    $referer=parse_url($_SERVER['HTTP_REFERER'], PHP_URL_PATH);
+    if (basename($referer) == "index.php")
+        unset($_SESSION['HTTP_REFERER']);
+    else if ($referer != $_SERVER['PHP_SELF'])
+        $_SESSION['HTTP_REFERER'] = $_SERVER['HTTP_REFERER'];
+}
+
 page($_SESSION['page_title'], false, false, '', $js);
 
 //-----------------------------------------------------------------------------------------------
@@ -78,9 +89,9 @@ if (isset($_GET['AddedID']))
 
     display_note(get_gl_view_str($trans_type, $trans_no, _("&View the GL Postings for this Payment")));
 
-    hyperlink_params($_SERVER['PHP_SELF'], _("Enter Another &Payment"), "NewPayment=yes");
+    hyperlink_params($_SERVER['PHP_SELF'], _("Enter Another &Payment"), "NewPayment=yes&date_=".$_GET['date_']."&bank_account=".$_POST['bank_account']);
 
-    hyperlink_params($_SERVER['PHP_SELF'], _("Enter A &Deposit"), "NewDeposit=yes");
+    hyperlink_params($_SERVER['PHP_SELF'], _("Enter A &Deposit"), "NewDeposit=yes&date_=".$_GET['date_']."&bank_account=".$_POST['bank_account']);
 
     hyperlink_params("$path_to_root/admin/attachments.php", _("Add an Attachment"), "filterType=$trans_type&trans_no=$trans_no");
 
@@ -112,9 +123,9 @@ if (isset($_GET['AddedDep']))
 
     display_note(get_gl_view_str($trans_type, $trans_no, _("View the GL Postings for this Deposit")));
 
-    hyperlink_params($_SERVER['PHP_SELF'], _("Enter Another Deposit"), "NewDeposit=yes");
+    hyperlink_params($_SERVER['PHP_SELF'], _("Enter Another Deposit"), "NewDeposit=yes&date_=".$_GET['date_']."&bank_account=".$_POST['bank_account']);
 
-    hyperlink_params($_SERVER['PHP_SELF'], _("Enter A Payment"), "NewPayment=yes");
+    hyperlink_params($_SERVER['PHP_SELF'], _("Enter A Payment"), "NewPayment=yes&date_=".$_GET['date_']."&bank_account=".$_POST['bank_account']);
 
     display_footer_exit();
 }
@@ -197,7 +208,10 @@ function create_cart($type, $trans_no)
 
     } else {
         $cart->reference = $Refs->get_next($cart->trans_type, null, $cart->tran_date);
-        $cart->tran_date = new_doc_date();
+            if (isset($_GET['date_']))
+                    $cart->tran_date  = $_GET['date_'];
+                else
+                    $cart->tran_date = new_doc_date();
         if (!is_date_in_fiscalyear($cart->tran_date))
             $cart->tran_date = end_fiscalyear();
     }
@@ -300,6 +314,16 @@ if (isset($_POST['Process']) && !check_trans())
 
     $trans_type = $trans[0];
        $trans_no = $trans[1];
+
+        // retain the reconciled status if desired by user
+        if (isset($_POST['reconciled'])
+            && $_POST['reconciled'] == 1) {
+            $sql = "UPDATE ".TB_PREF."bank_trans SET reconciled=".db_escape($_POST['reconciled_date'])
+                ." WHERE type=" . $trans_type . " AND trans_no=".db_escape($trans_no);
+
+            db_query($sql, "Can't change reconciliation status");
+        }
+
     new_doc_date($_POST['date_']);
 
     $_SESSION['pay_items']->clear_items();
@@ -307,12 +331,27 @@ if (isset($_POST['Process']) && !check_trans())
 
     commit_transaction();
 
-    if ($new)
-        meta_forward($_SERVER['PHP_SELF'], $trans_type==ST_BANKPAYMENT ?
-            "AddedID=$trans_no" : "AddedDep=$trans_no");
-    else
-        meta_forward($_SERVER['PHP_SELF'], $trans_type==ST_BANKPAYMENT ?
-            "UpdatedID=$trans_no" : "UpdatedDep=$trans_no");
+    $params = "";
+    $referer = "";
+    if (!isset($_SESSION['HTTP_REFERER'])) {
+        $referer=$_SERVER['PHP_SELF'];
+        if ($new) {
+            $params .= ($trans_type==ST_BANKPAYMENT ?  "AddedID=" : "AddedDep=");
+            $params .= "$trans_no&date_=".$_POST['date_']."&bank_account=".$_POST['bank_account'];
+        } else
+            $params .= ($trans_type==ST_BANKPAYMENT ?
+                "UpdatedID=$trans_no" : "UpdatedDep=$trans_no");
+    } else {
+        $referer=parse_url($_SESSION['HTTP_REFERER'], PHP_URL_PATH);
+        $params = parse_url(htmlspecialchars_decode($_SESSION['HTTP_REFERER']), PHP_URL_QUERY);
+        $params = preg_replace('/[&]*message.*/', '', $params);
+        if (!empty($params))
+            $params .= "&";
+        $params .= "message=";
+        $params .= ($trans_type==ST_BANKPAYMENT ? "Payment" : "Deposit");
+        $params .= " Completed";
+    }
+    meta_forward($referer, $params);
 
 }
 

Somehow my cut and paste did more cutting than pasting.

@@ -26,10 +26,35 @@ if (user_use_date_picker())
 if ($SysPrefs->use_popup_windows)
     $js .= get_js_open_window(800, 500);
     
+if (isset($_GET['trans_no'])
+    && isset($_GET['filterType'])) {
+    $_POST['FromTransNo'] = $_POST['ToTransNo'] = $_POST['selected_id'] = $_POST['trans_no'] = $_GET['trans_no'];
+    $_POST['filterType'] = $_GET['filterType'];
+    $_POST['ProcessVoiding'] = true;
+}
+
+$referer=parse_url($_SERVER['HTTP_REFERER'], PHP_URL_PATH);
+if (basename($referer) == "index.php")
+    unset($_SESSION['HTTP_REFERER']);
+else if ($referer != $_SERVER['PHP_SELF'])
+    $_SESSION['HTTP_REFERER'] = $_SERVER['HTTP_REFERER'];
+
 page(_($help_context = "Void a Transaction"), false, false, "", $js);
 
 simple_page_mode(true);
 //----------------------------------------------------------------------------------------
+function returnToReferer($message)
+{
+    $referer=parse_url($_SESSION['HTTP_REFERER'], PHP_URL_PATH);
+    $params = parse_url(htmlspecialchars_decode($_SESSION['HTTP_REFERER']), PHP_URL_QUERY);
+    $params = preg_replace('/&message.*/', '', $params);
+    if (!empty($params))
+        $params .= "&";
+    $params .= "message=$message";
+
+    meta_forward($referer, $params);
+}
+
 function exist_transaction($type, $type_no)
 {
     $void_entry = get_voided_entry($type, $type_no);
@@ -287,6 +312,9 @@ function handle_void_transaction()
 
         if (!$msg) 
         {
+            if (isset($_SESSION['HTTP_REFERER']))
+                returnToReferer("Void Completed");
+
             display_notification_centered(_("Selected transaction has been voided."));
             unset($_POST['trans_no']);
             unset($_POST['memo_']);
@@ -324,6 +352,8 @@ if (isset($_POST['ConfirmVoiding']))
 
 if (isset($_POST['CancelVoiding']))
 {
+    if (isset($_SESSION['HTTP_REFERER']))
+        returnToReferer("Void Canceled");
     $selected_id = -1;
     $Ajax->activate('_page_body');
 }

The delete button is a separate core feature.   To add that, change void_transaction:

+++ b/core/admin/void_transaction.php
@@ -26,10 +26,35 @@ if (user_use_date_picker())
 if ($SysPrefs->use_popup_windows)
        $js .= get_js_open_window(800, 500);
        
+if (isset($_GET['trans_no'])
+    && isset($_GET['filterType'])) {
+    $_POST['FromTransNo'] = $_POST['ToTransNo'] = $_POST['selected_id'] = $_POST['trans_no'] = $_GET['trans_no'];
+}

 page(_($help_context = "Void a Transaction"), false, false, "", $js);

Then if you want control to return back to the inquiry page (in this case, bank g/l inquiry) after the delete, you can add the http referer core feature.  The code for both feature adds is:

@@ -26,10 +26,35 @@ if (user_use_date_picker())
 if ($SysPrefs->use_popup_windows)
        $js .= get_js_open_window(800, 500);
        
+if (isset($_GET['trans_no'])
+    && isset($_GET['filterType'])) {
+    $_POST['FromTransNo'] = $_POST['ToTransNo'] = $_POST['selected_id'] = $_POST['trans_no'] = $_GET['trans_no'];
+}
+
+$referer=parse_url($_SERVER['HTTP_REFERER'], PHP_URL_PATH);
+if (basename($referer) == "index.php")
+    unset($_SESSION['HTTP_REFERER']);
+else if ($referer != $_SERVER['PHP_SELF'])
+    $_SESSION['HTTP_REFERER'] = $_SERVER['HTTP_REFERER'];
+
 page(_($help_context = "Void a Transaction"), false, false, "", $js);
 
 simple_page_mode(true);
 //----------------------------------------------------------------------------------------
+function returnToReferer($message)
+{
+    $referer=parse_url($_SESSION['HTTP_REFERER'], PHP_URL_PATH);
+    $params = parse_url(htmlspecialchars_decode($_SESSION['HTTP_REFERER']), PHP_URL_QUERY);
+    $params = preg_replace('/&message.*/', '', $params);
+    if (!empty($params))
+        $params .= "&";
+    $params .= "message=$message";
+
+    meta_forward($referer, $params);
+}
+
 function exist_transaction($type, $type_no)
 {
        $void_entry = get_voided_entry($type, $type_no);
@@ -287,6 +312,9 @@ function handle_void_transaction()
 
                if (!$msg) 
                {
+            if (isset($_SESSION['HTTP_REFERER']))
+                returnToReferer("Void Completed");
+
                        display_notification_centered(_("Selected transaction has been voided."));
                        unset($_POST['trans_no']);
                        unset($_POST['memo_']);
@@ -324,6 +352,8 @@ if (isset($_POST['ConfirmVoiding']))
 
 if (isset($_POST['CancelVoiding']))
 {
+    if (isset($_SESSION['HTTP_REFERER']))
+        returnToReferer("Void Canceled");
        $selected_id = -1;
        $Ajax->activate('_page_body');
 }

Sales Type Summary Report is based on report 309 (Sales Summary Report) but adds the ability to filter on sales type.  It collapses price (one line per item rather than one line per item/price) and sorts by item description rather than item number.  Both reports should always have the same total.

Use the original report if you are interested in seeing sales by price breakdown.   Use Sales Type Summary if you are interested in seeing sales by sales type.

I have defined several sales types (wholesale, retail, ...) in my installation and I have to report these sales separately on government reports.   (Reporting sales by tax group would also be useful).  I am not interested in seeing price breakdowns.

There isn't an updated pull request.

This feature (among others) is in my production code base at https://github.com/braathwaate/frontac24 in the wwh branch.   By searching for "ajax sync" in the commits you could find some of the changes.  I admit this is confusing.  I made changes under other commit names, so you won't find everything this way.

One improvement was adding a nocache parameter to the core page() function.  The inquiry functions set this, so that after a return to the inquiry page after an edit, the page refreshes and shows the updated transaction, still using the same search parameters originally set by the user.

Try removing the scroll_down() call.

Yes, this is a bug.  Add "type" to the array in get_js_history() and set_posts()

The original pull request is out-of-date.  As stated therein, many pages would benefit from the concept, and not all was implemented at that time.   There have been other bug fixes and improvements to it.

Replace

label_cell(payment_person_name_link($myrow["person_type_id"],$myrow["person_id"], true, get_post("TransAfterDate"),get_post("TransToDate")));

with

label_cell(payment_person_name($myrow["person_type_id"],$myrow["person_id"], true));

The delivery picklist will not be useful in its current state because it is hard coded for a current sales type, makes custom numeric calculations, and relies on a checkbox enhancement in the core.

The only change in  the customer statement report is to display the customer check number for a customer payment, given that one enters this in the memo field of the customer payment.    No one will find this useful unless they follow that procedure.

238

(5 replies, posted in Setup)

Good to know.  The setting can be made in the $opts array (fifth argument):

stock_items_list('stock_id', null, false, false, array('where'=>'s.category_id='.$filter_cat));

Well, I am at a loss to say anything further.

I am still guessing you neglected to create a "bank account" for your "credit card" (https://frontaccounting.com/fawiki/index.php?n=Help.BankAccounts).

I am then guessing you are trying to directly use the General Journal to directly enter CC expenses using the CC G/L account rather than using Supplier payment or Bank Payment.

That can work, except if you create any suppliers with that CC card as the accounts payable account, which apparently you have done.   I don't think putting the CC G/L account into the supplier is helping you any, and is causing the GJ counterparty problem using this mode of operation.    If you just want to mark the supplier as being paid by CC for informational purposes, you can do that in the supplier bank account field.

Sorry I haven't been able to help.

FA does not have a way to assign a bank (or cc) account to a particular supplier that would pop up when the supplier is selected for payment.   I suppose it would be a nice feature if it would do this, although I personally would not use it because the only suppliers that have my credit card are periodic payments like electricity, subscriptions, etc and I handle that with an auto pay extension.

Using the payables account in the manner you have described is unusual because normally a cc card would be used to pay for a variety of G/L accounts, for example, utilities, insurance, consumables, auto & travel, etc.   When a payment is made, the payables account would be one of these G/L accounts and the bank account would be the cc card.

I agree that this is an inconsistency.   Journal entry requires a supplier/customer counter party for A/P accounts but payment entry allows quick entry and miscellaneous counter party for A/P accounts.

Usually the supplier would have the default A/P account or a G/L expense account.  Then to pay a supplier (without use a P/O), you would use bank account payment entry and set the From: to the CC account (which was set up as a bank account).

So there is nothing wrong with putting the vendor purchase on a CC card, if it was set up as a bank account.  But it appears to me that you are trying to use the CC card G/L account directly, and you put that G/L account on the supplier default Payable account.

243

(4 replies, posted in Accounts Payable)

If you need a discount amount (instead of a percentage), just Allow Negative Prices in System G/L setup, create a discount item, and add that to the sales order.    See https://frontaccounting.com/fawiki/index.php?n=Help.TaxTypes.

I looked at the modify code today and it voids out the old G/L transactions.  So now I'm thinking that perhaps all you need to do is modify the invoice and reprocess it.

Voiding the invoices, re-entering them, and then reapplying the payments may be the only way to fix the wrong sales account using vanilla FA.

However, the sales orders from the voided invoices will live on forever because they cannot be canceled due to this bug: http://mantis.frontaccounting.com/view.php?id=4155, although the only ill effect is seeing 0 amount sales orders appear during searches or reports.   Sales orders also cannot be voided.

Using a journal entry would be the fastest and easiest vanilla FA way to fix the problem, but I do not think it would work because it does not support counterparty on sales accounts (a feature I added to my fork).

The inability to edit invoiced sales orders is a continual irritant to my staff who need to change the content of sales orders for various reasons.  FA's philosophy is that the invoice is a contract with the customer and should not be changed.  FA only allows a few changes such as date.

If the bank account is listed in a supplier as an accounts payable account or in a customer as an accounts receivable account, the counterparty field shows up.   So if you do not want the counterparty field, then find the supplier/customer and change it to go to a different account.  If you want to use a different counterparty, then add that bank account to that supplier/customer.

I am also unable to understand the logic behind this feature and the mysterious work-around and I recently posted a bug report which is related.  http://mantis.frontaccounting.com/view.php?id=4475.  Along with the report, I took a crack at fixing this bug simply by removing the subtype per-line check.

I finally realized now what you are doing: importing opening balances from another ERP and dividing the AR/AP account balances into separate balances for each customer/supplier.  Thus your mod adding person_id to the import makes sense.  Future customer payments then can be applied against the AR established by the journal entry.  I tested this just to make sure it works and it does.  I am guessing that it works for AP as well.

Indeed, this approach is more intuitive than the one mentioned in the wiki and I recommend that the wiki be updated to mention this approach. 

Ignore my prior post because I was speaking to import transactions from another ERP (i.e. the entire general journal).   The problem with that style of import is that FA assigns counterparty to payments/AR but not to sales/AR, resulting in the overpaid issue as described.

To me, importing customer/supplier (person) info into FA is deceptively simple.

1. To do this import, first one must know the person_id, which requires some kind of lookup by name.
2. By adding person_id, I am guessing that FA creates customer/supplier records.  If so, you will see these by doing customer/supplier inquiry.
3. Imported payments will have no FA invoices, so no allocations against invoices are made.
4. Thus, after the import, customer/supplier accounts will appear to have been overpaid, although the AR/AP G/L accounts should be correct.  But I would have guessed that this would have been the case even without the person_id, so I am confused at what trial balance account was fixed by adding person_id.

If this is not the case, and somehow your customer/supplier accounts appear correct after the import, you have discovered something that I do not know.

Otherwise, the question then becomes how to correct the customer/supplier accounts.  I don't have an easy answer.

A. Creating dummy customer/supplier invoices in FA may work, but I think that may double the sales and A/R G/L accounts, so may require a GJ entry to fix that.

B. What I did:

B.1. zero out the amounts in the customer trans db after the import to get zero balances. 

B.2. Double enter new payments from pre-import invoices into both FA and the old ERP.

B.3. FA payments were entered using a GJ entry against AR and the appropriate bank account so as not to affect the zero customer balance.

B.4 New invoices and payments were entered in FA and eventually the customer balances became correct.

B.5 update the suppler trans database to make all transactions allocated.

I don't use this feature, but looking at the code, I am guessing the rotating icon come on during submit, which has a short Ajax timeout.

To use the long Ajax timeout (and display the horizontal time icon like in backup) change:

        submit_center_first('confirmed'.$id, _('Create'), _('Create recurrent invoices'), false, ICON_OK);
to:

        submit_center_first('confirmed'.$id, _('Create'), _('Create recurrent invoices'), "process", ICON_OK);

Note: this really needs to be configurable on a page by page basis rather than hard-coding it, because people keep running into this problem on various pages as their usage of FA grows.  Or the timeout needs to pop-up an alert asking the user if they want to continue or cancel.  Or ajax needs to check if progress is actually being made and eliminate the timeout.

Finally, if you get past that timeout, then php also has a timeout.