1 (edited by LUTi 12/27/2010 02:43:13 pm)

Topic: Edit Supplier Invoice

I know supplier invoices shouldn't be edited, as this can easily make a mess in inventory (and COGS calculations). But, what about the case when it is the last transaction, so nothing would actually change if we make some correction (for example, we've found a typo when we've printed the invoice after it has been posted; or, we want just to edit a memo, or a product description, which wouldn't actually change anything...)?

The option to void such a transaction and type all over again I don't find very convenient. So, I've adapted the "supplier invioce form" so I can "open" some previously entered invoice, make corrections and repost it. At this stage, I actually void the previous invoice (with the date of that transaction), and post a new version of the invoice.

I know it is not the exact solution for the case above, but it is something I was able to do (seems to work for me, as much as I was able to test up to now...). To be able to achieve to actually edit the existing invoice and repost it (with the old ID), if it can be done safely (no transactions after it yet, or some insignificant changes that don't affect stock), I should have a more in-depth knowledge about FA (and, MySQL and PHP) - which unfortunately I don't. So, any help in this direction is more than welcome (what to check to be sure that it is the last transaction, and what would be the most convenient way to make modifications).

In any case, below is my code (modifications). Any feedback is more than welcome, in particular if I've done something I shouldn't (so I can introduce some inconsistency in the database using this).

=============================================================================================

--- gl/inquiry/journal_inquiry.php.ORIGINAL    2010-12-10 14:12:42.000000000 +0100
+++ gl/inquiry/journal_inquiry.php        2010-12-27 13:50:52.000000000 +0100
@@ -94,7 +94,7 @@ $editors = array(
    ST_CUSTDELIVERY => "/sales/customer_delivery.php?ModifyDelivery=%d",
//   16=> Location Transfer,
//   17=> Inventory Adjustment,
-//   20=> Supplier Invoice,
+   ST_SUPPINVOICE => "/purchasing/supplier_invoice.php?ModifySI=Yes&trans_no=%d",
//   21=> Supplier Credit Note,
//   22=> Supplier Payment,
//   25=> Purchase Order Delivery,
--- purchasing/supplier_invoice.php.ORIGINAL    2010-12-10 14:12:44.000000000 +0100
+++ purchasing/supplier_invoice.php        2010-12-27 13:43:49.000000000 +0100
@@ -25,7 +25,64 @@ if ($use_popup_windows)
    $js .= get_js_open_window(900, 500);
if ($use_date_picker)
    $js .= get_js_date_picker();
-page(_($help_context = "Enter Supplier Invoice"), false, false, "", $js);
+
+if (isset($_GET['ModifySI'])) {
+    $help_context = "Modifying Supplier Invoice";
+    $error_msg = '';
+
+    if (isset($_GET["trans_no"])) {
+        $trans_no = $_GET["trans_no"];
+    }
+    elseif (isset($_POST["trans_no"])) {
+        $trans_no = $_POST["trans_no"];
+    }
+    else    $trans_no = null;
+
+    if ($trans_no != null) {
+        $_SESSION['page_title'] = sprintf(_("Modifying Supplier Invoice # %d."), $trans_no);
+        if (is_closed_trans(ST_SUPPINVOICE, $trans_no)) {
+            $error_msg = _("The selected transaction was closed for edition.");
+        }
+        else {
+            $void_entry = get_voided_entry(ST_SUPPINVOICE, $trans_no);
+            if ($void_entry != null) {
+                $error_msg = _("The selected transaction has already been voided.");
+            }
+            else {
+                $result = get_gl_trans(ST_SUPPINVOICE, $trans_no);
+                if (db_num_rows($result) == 0) {
+                    $error_msg = _("Cannot find Supplier Invoice # ") . $trans_no;
+                }
+            }
+        }
+    }
+    else {
+        $_SESSION['page_title'] = _("Modifying Supplier Invoice (with missing #).");
+        $error_msg = _("Supplier Invoice # is missing!");
+    }
+
+    if ($error_msg == '') {
+        $supp_trans = new supp_trans(ST_SUPPINVOICE);
+        read_supp_invoice($trans_no, ST_SUPPINVOICE, $supp_trans);
+        page($_SESSION['page_title'], false, false,'', $js);
+        $_SESSION['supp_trans'] = $supp_trans;
+        $_SESSION['inv_modify'] = true;
+        $_SESSION['old_trans'] = $trans_no;
+        $_SESSION['old_date'] = $supp_trans->tran_date;
+    }
+    else {
+        $_SESSION['inv_modify'] = false;
+        $_SESSION['old_trans'] = null;
+        $_SESSION['old_date'] = null;
+        page($_SESSION['page_title'], false, false,'', $js);
+        display_error($error_msg);
+        end_page(true);
+        exit;
+    }
+}
+else {
+    page(_($help_context = "Enter Supplier Invoice"), false, false, "", $js);
+}

//----------------------------------------------------------------------------------------

@@ -193,6 +250,27 @@ function check_data()

//--------------------------------------------------------------------------------------------------

+function handle_void_invoice()
+{
+
+    if (!exists_supp_trans(ST_SUPPINVOICE, $_SESSION['old_trans']))
+        return false;
+    if (!post_void_supp_trans(ST_SUPPINVOICE, $_SESSION['old_trans']))
+        return false;
+
+    $ret = void_transaction(ST_SUPPINVOICE, $_SESSION['old_trans'], $_SESSION['old_date'], 'Invoice Modification - Old (Voided) Version');
+
+    if ($ret)
+    {
+        display_notification_centered(_("Old invoice has been voided."));
+    }
+    else {
+        display_error(_("Old invoice cannot be voided."));
+        set_focus('trans_no');
+    }
+    return $ret;
+}
+
function handle_commit_invoice()
{
    copy_to_trans($_SESSION['supp_trans']);
@@ -212,7 +290,15 @@ function handle_commit_invoice()

if (isset($_POST['PostInvoice']))
{
-    handle_commit_invoice();
+    if ($_SESSION['inv_modify']) {
+        if (handle_void_invoice($_SESSION['old_trans'], $_SESSION['old_date'])) {
+            display_notification_centered(_("New invoice data:<br>") . print_r($_SESSION['supp_trans'], TRUE) . "<br>");
+            handle_commit_invoice();
+        }
+    }
+    else {
+        handle_commit_invoice();
+    }
}

function check_item_data($n)

=============================================================================================

Re: Edit Supplier Invoice

I make mistakes on purchase invoices (and customer sales invoices) too.  What is the best, fastest (time is important), easiest to fix the errors? 

Is the above a reasonable solution or is something else better?

Making an entry error on a form happens regularly so some way is needed to solve this problem of lousy typists.  Simply voiding and retyping the invoice seems open to making some other error as opposed to editing an existing invoice.

Thanks

Re: Edit Supplier Invoice

Yes, lack of purchase invoice edition is  annoying. I hope this will be added in some minor 2.3 release.
Janusz

4 (edited by LUTi 01/16/2011 07:42:41 pm)

Re: Edit Supplier Invoice

By the way, my temporary solution above can be tricky. After you edit one invoice, some sessin variables remain set, so some extra lines have to be added to prevent any new invoice added after (within the same session) to be voided imediately.

My latest patch (for 2.3.0) is:

=============================================================================================================
--- purchasing/supplier_invoice.php.ORIGINAL    2010-12-10 14:12:44.000000000 +0100
+++ purchasing/supplier_invoice.php        2010-12-27 22:28:52.000000000 +0100
@@ -25,7 +25,73 @@ if ($use_popup_windows)
    $js .= get_js_open_window(900, 500);
if ($use_date_picker)
    $js .= get_js_date_picker();
-page(_($help_context = "Enter Supplier Invoice"), false, false, "", $js);
+
+if (isset($_GET['ModifySI'])) {
+//display_notification_centered(_("Modify SI TRUE<br>"));
+    $help_context = "Modifying Supplier Invoice";
+    $error_msg = '';
+
+    if (isset($_GET["trans_no"])) {
+        $trans_no = $_GET["trans_no"];
+    }
+    elseif (isset($_POST["trans_no"])) {
+        $trans_no = $_POST["trans_no"];
+    }
+    else    $trans_no = null;
+
+    if ($trans_no != null) {
+        $_SESSION['page_title'] = sprintf(_("Modifying Supplier Invoice # %d."), $trans_no);
+        if (is_closed_trans(ST_SUPPINVOICE, $trans_no)) {
+            $error_msg = _("The selected transaction was closed for edition.");
+        }
+        else {
+            $void_entry = get_voided_entry(ST_SUPPINVOICE, $trans_no);
+            if ($void_entry != null) {
+                $error_msg = _("The selected transaction has already been voided.");
+            }
+            else {
+                $result = get_gl_trans(ST_SUPPINVOICE, $trans_no);
+                if (db_num_rows($result) == 0) {
+                    $error_msg = _("Cannot find Supplier Invoice # ") . $trans_no;
+                }
+            }
+        }
+    }
+    else {
+        $_SESSION['page_title'] = _("Modifying Supplier Invoice (with missing #).");
+        $error_msg = _("Supplier Invoice # is missing!");
+    }
+
+    if ($error_msg == '') {
+        $supp_trans = new supp_trans(ST_SUPPINVOICE);
+        read_supp_invoice($trans_no, ST_SUPPINVOICE, $supp_trans);
+        page($_SESSION['page_title'], false, false,'', $js);
+        $_SESSION['supp_trans'] = $supp_trans;
+        $_SESSION['inv_modify'] = true;
+        $_SESSION['old_trans'] = $trans_no;
+        $_SESSION['old_date'] = $supp_trans->tran_date;
+    }
+    else {
+        $_SESSION['inv_modify'] = false;
+        $_SESSION['old_trans'] = null;
+        $_SESSION['old_date'] = null;
+        page($_SESSION['page_title'], false, false,'', $js);
+        display_error($error_msg);
+        end_page(true);
+        exit;
+    }
+}
+elseif (isset($_GET['New'])) {
+//display_notification_centered(_("New TRUE, Modify SI FALSE<br>"));
+    $_SESSION['inv_modify'] = false;
+    $_SESSION['old_trans'] = null;
+    $_SESSION['old_date'] = null;
+    page(_($help_context = "Enter Supplier Invoice"), false, false, "", $js);
+}
+else {
+//display_notification_centered(_("Modify SI unchanged...<br>"));
+    page(_($help_context = "Enter Supplier Invoice"), false, false, "", $js);
+}

//----------------------------------------------------------------------------------------

@@ -193,6 +259,27 @@ function check_data()

//--------------------------------------------------------------------------------------------------

+function handle_void_invoice()
+{
+
+    if (!exists_supp_trans(ST_SUPPINVOICE, $_SESSION['old_trans']))
+        return false;
+    if (!post_void_supp_trans(ST_SUPPINVOICE, $_SESSION['old_trans']))
+        return false;
+
+    $ret = void_transaction(ST_SUPPINVOICE, $_SESSION['old_trans'], $_SESSION['old_date'], 'Invoice Modification - Old Version');
+
+    if ($ret)
+    {
+        display_notification_centered(_("Old invoice has been voided."));
+    }
+    else {
+        display_error(_("Old invoice cannot be voided."));
+        set_focus('trans_no');
+    }
+    return $ret;
+}
+
function handle_commit_invoice()
{
    copy_to_trans($_SESSION['supp_trans']);
@@ -212,7 +299,14 @@ function handle_commit_invoice()

if (isset($_POST['PostInvoice']))
{
-    handle_commit_invoice();
+    if ($_SESSION['inv_modify']) {
+        if (handle_void_invoice($_SESSION['old_trans'], $_SESSION['old_date'])) {
+            handle_commit_invoice();
+        }
+    }
+    else {
+        handle_commit_invoice();
+    }
}

function check_item_data($n)
=============================================================================================================

Patch for gl/inquiry/journal_inquiry.php above is OK (and also needed).


Also be careful If you open another tab in your browser with another invoice in between (while you "edit" one invoice). I think session variables mix up and results are unpredictable (in any case things are not as they should be). This should somehow be resolved before I could consider my patch really usable. So, take care before using this solution (altough it seems to work otherwise...).

In any case, I hope as well there will be a safe solution in the near future available.

Re: Edit Supplier Invoice

can You maybe share the modified files?

6 (edited by LUTi 04/04/2011 01:14:04 pm)

Re: Edit Supplier Invoice

The latest made is above (post #4). I haven't done it for the latest release, because it may be too dangerous for me to use it, as it is now (I like to have multiple windows opened at the same time, to copy/paste data...).

I have to figure out how to do it more safe before I could use it, or simply wait that the developers provide some solution. By the way, Joe, what are the plans about this subject (I see in demo 2.4 CVS there is still no option to edit supplier invoice...)? I am waiting this to be resolved, and then I am almost ready (another feature is GIFI field implementation, but I believe I can do GIFI based balences / reports in MySQL / manually somehow, if everything else will be OK...) to consider switching to FrontAccounting for my production environment (I am still at SQL Ledger for that at the moment, and try to do tests in parallel as much as my time permits...).

For sure I will publish here if I manage to achieve some progress, but am quite short on time recently (not to mention that I don't know exactly how to proceed to make variables being kept per instance, not per session, what I believe is a problem with my "solution" now...).

Re: Edit Supplier Invoice

Yes, lack of time suffers all of us smile.
Regarding 'variables being kept per instance'  you can use sys_prefs table (if  you mean company level settings).

Re: Edit Supplier Invoice

so once a supplier invoice has been entered there is no way in the system to make any corrections? ie when the per item price is incorrectly entered I try to go back to the invoice to either correct the price - which can't be edited, or delete the item but it returns an error message which says that the items have already been delivered. When I go to void a transaction it voids the transaction but the items remain in the inventory... Why is there no way to edit a supplier invoice once it's been entered?

9 (edited by LUTi 04/11/2011 02:01:55 pm)

Re: Edit Supplier Invoice

I doubt that sys_prefs table could be of any use for my problem.

If you look at my code above, you can see I am using _SESSION variables, as you did (in original file). These are exactly the same in the first instance, in the second instance and so on (if I click edit the invoice more than just once - to have one instance to work on it, and post it at the end, but have another / unmodified version till the end to copy something out of it, or to post it as another new invoice, or whatever...).

I've thought to concatenate a random string to their names, but can not do that as I should do it only the first time (when already posted invoice is read), but not later anymore (next time something is changed and the screen is refreshed, but invoice not saved / posted yet). On the other hand, I would need to know their names (containing random string) next time, to be able to read them.

So, I see no way to have them different for one and another window within the same session.

Is there an easy way to have some variables kept between form submits for each window instance separately, and not for the session. I mean, without passing all of them all the time with GET / POST, when the form is submitted (as it is now)?

The way I've intended to resolve it above, my changes were relatively simple and safe, as I haven't directly save no information (I was just preprocessed the form for the new invoice) in the database. All critical code is still yours. If I should change it more in depth, I'm afraid I would do something incomplete / wrong, without being even aware of that (you know all the logic about what goes where, but I have absolutely not a clear picture about that!).

Is it a bit more clear to you what is my problem now? I'm sorry, but have no idea how to explain it in a better way...

Re: Edit Supplier Invoice

I'm not sure if I understand you right, but this application does not allow to open more than one transaction at the same time. When you edit e.g. Sales Invoice cart variable $_SESSION['Items'] is created and application use it during data entry. When you open the Sales Order again the session variable is just overwritten. Some workaround is to open the document in another browser (if you have two on your box wink ). Every browser has its own cache for cookies so they open separate sessions.
Janusz

Re: Edit Supplier Invoice

Maybe it would be good to consider to redesign it to enable more opened forms (the same ones) within one browser? It is a bit unsafe, as it is now, or? In particular if different forms do share some session variables. I may open a new window unintentionally (right click instead of left - I have this habit as I generally like to simply close some windows later instead of scrolling back and look for some previous page...), or sometimes even need to do (check / enter / edit) something in some other form.

It should not be too hard, or? To pass all form variables as arguments, instead of keeping them as session variables...

Thank you for a suggestion about more browsers anyway. ;-)

Re: Edit Supplier Invoice

No, this is not so easy. This is really unsafe to send all the data back and forth between server and browser. This way all security role related constraints are broken. Session is saved using session id in cookie which are shared by all browser's tabs/windows. So far I have not found easy and secure way to skip this restriction.
Janusz

Re: Edit Supplier Invoice

Wouldn't it be possible to encrypt the data transmitted? There could (should) be only one user (security role) per session, of course.

Or, to somehow attach some form ID to variable names, when a new form is opened for the first time, and pass only this information to the server and back later (when data is changed / edited)?

In any case, to distinguish one form window from the other (speaking about the same form). I'd say this could be really useful in many situations...

Re: Edit Supplier Invoice

Frankly speaking I see no real issue with the constraint of single editor window for given transaction type. If you really need to see another transaction at the same time you can just open popup window from transactions inquiry. This popup is not editable, but you can see all the content here without edition conflict.

This is really not worth the time spent on design and development (I really tried many variants), but if you will find any really working implementation - give me a note.  We can adopt it in FA.
Janusz