If anyone has interest in receiving Bitcoin Payments as USD with zero fee to the merchant (you never touch BTC asset). I just created a open source web app written in php under the MIT Lic.

It has a FrontAccounting plugin with automated accounting support. Everything is  completely documented in the git wiki.

It is compatible with payments from any (custodial or non custodial) bitcoin lighting wallet (Cash App, Strike, Blue Wallet etc.) from anywhere in the world.

The git is here:
https://github.com/trafficpest/strikeout

Wiki is here:
https://github.com/trafficpest/strikeout/wiki

Screenshots here:
https://github.com/trafficpest/strikeou … Sceenshots

52

(1 replies, posted in Wish List)

I think it would be useful to add string text field or drop drown box w/options and use strtotime() to add more function to recurrent invoices. If you had the field you could put days in not just dates. ie first monday or last wednesday. This would be really usefull for service based industries that have a regular work week and schedule clients regularly based on day of the week. ie therapists or home service companies.

keep the rest the same month and day with optional field that would calculate the next date after month and day is calculated.

I have integrated Btc pay server for bitcoin payments into frontaccounting. It has web hooks and does the accounting on the backend through sql. if you are interested let me know. I was going to release it as a one click install with frontaccounting as a  docker container for umbrel. so people can easily self host payments and bitcoin node and accounting


https://docs.btcpayserver.org/Deployment/

https://umbrel.com/

Frontaccounting is accounting software not a payment integration. Development should be on accounting issues

Ok so I copied all the persons for each branch and it still fails. There is something else going on here.

/sales/manage/customer_branches.php

will fail and hang on large numbers of branches for clients ( 745 branches)
fetch time for any client increases if more branches are made even for other clients. I think the issue might be is our same crm persons are listed on the other customer branches in crm contacts.

Example
Debtor (MHN Health Net Insurance)
Branch (MHN Patient Jim) -> Crm Person (Patient Jim)

Debtor (Anthem Blue Cross)
Branch (Anthem Patient Jim) -> Crm Person (Patient Jim)

Person is the same that both branches are referencing so they both point to the same ID.

SQL Called on page

SET sql_mode = 'STRICT_ALL_TABLES'
SELECT name, value FROM 0_sys_prefs
SELECT value FROM 0_sys_prefs WHERE name='version_id'
SELECT name, value FROM 0_sys_prefs
SELECT COUNT(*) FROM 0_debtors_master
SELECT COUNT(*) FROM 0_salesman
SELECT COUNT(*) FROM 0_areas
SELECT COUNT(*) FROM 0_shippers
SELECT COUNT(*) FROM 0_tax_groups
SELECT debtor_no, debtor_ref, curr_code, inactive FROM 0_debtors_master  ORDER BY debtor_ref
SELECT COUNT(*) FROM 0_cust_branch WHERE debtor_no='757'
SELECT COUNT(*) FROM (SELECT b.branch_code, b.branch_ref, b.br_name, p.name as contact_name, s.salesman_name, a.description, p.phone, p.fax, p.email, t.name AS tax_group_name, b.inactive
        FROM 0_cust_branch b LEFT JOIN 0_crm_contacts c
            ON c.entity_id=b.branch_code AND c.type='cust_branch' AND c.action='general'
            LEFT JOIN 0_crm_persons p on c.person_id=p.id,0_areas a, 0_salesman s, 0_tax_groups t
        WHERE b.tax_group_id=t.id
        AND b.area=a.area_code
        AND b.salesman=s.salesman_code
        AND b.debtor_no = '757' AND !b.inactive GROUP BY b.branch_code ORDER BY branch_ref) tmp_count
SELECT b.branch_code, b.branch_ref, b.br_name, p.name as contact_name, s.salesman_name, a.description, p.phone, p.fax, p.email, t.name AS tax_group_name, b.inactive
     FROM 0_cust_branch b LEFT JOIN 0_crm_contacts c
            ON c.entity_id=b.branch_code AND c.type='cust_branch' AND c.action='general'
            LEFT JOIN 0_crm_persons p on c.person_id=p.id,0_areas a, 0_salesman s, 0_tax_groups t
      WHERE (b.tax_group_id=t.id
        AND b.area=a.area_code
        AND b.salesman=s.salesman_code
        AND b.debtor_no = '757' AND !b.inactive) GROUP BY b.branch_code ORDER BY branch_ref LIMIT 0, 10
SELECT name, address, debtor_ref
        FROM 0_debtors_master WHERE debtor_no = '757'
SELECT salesman_code, salesman_name, inactive FROM 0_salesman ORDER BY salesman_name
SELECT area_code, description, inactive FROM 0_areas ORDER BY description
SELECT id, description, inactive FROM 0_groups ORDER BY description
SELECT loc_code, location_name, inactive FROM 0_locations WHERE fixed_asset=0 ORDER BY location_name
SELECT shipper_id, shipper_name, inactive FROM 0_shippers ORDER BY shipper_name
SELECT id, name, inactive FROM 0_tax_groups ORDER BY id
SELECT chart.account_code, chart.account_name, type.name, chart.inactive, type.id
            FROM 0_chart_master chart,0_chart_types type
            WHERE chart.account_type=type.id ORDER BY type.class_id,type.id,account_code
SELECT chart.account_code, chart.account_name, type.name, chart.inactive, type.id
            FROM 0_chart_master chart,0_chart_types type
            WHERE chart.account_type=type.id ORDER BY type.class_id,type.id,account_code
SELECT chart.account_code, chart.account_name, type.name, chart.inactive, type.id
            FROM (0_chart_master chart,0_chart_types type) LEFT JOIN 0_bank_accounts acc ON chart.account_code=acc.account_code
                WHERE acc.account_code  IS NULL
            AND chart.account_type=type.id ORDER BY type.class_id,type.id,account_code
SELECT chart.account_code, chart.account_name, type.name, chart.inactive, type.id
            FROM 0_chart_master chart,0_chart_types type
            WHERE chart.account_type=type.id ORDER BY type.class_id,type.id,account_code

Thanks for considering taking a look at this.
a though would be a branch select list with the first option for all branches then the other branches.

I can get it to output by branch by add this if statement to the loop

if ($_POST['BranchID'] == $myrow['branch_code']){
Blah blah do the table stuff here
}

but what is strange is the BranchID select box doesnt update any $_POST data?

only customer select and bank select appear to be working properly. To update $_POST['BranchID'] you have to select the branch then adjust the bank account to update it.

If you change the customer it will select the default first BranchID again so that works ok.

I have it outputting the Branch name in the table now. fairly easy

in
/includes/ui/allocation_cart.inc
in the function show_allocatable($show_totals)

add  Branch table header in the table loop pull the customer transaction data and add br name to the cell. This is how my function looks.

function show_allocatable($show_totals) {

    global $systypes_array;
    
    $k = $total_allocated = 0;

    $cart = $_SESSION['alloc'];
    $supp_ref = in_array($cart->type, array(ST_SUPPCREDIT, ST_SUPPAYMENT, ST_BANKPAYMENT));

    if (count($cart->allocs)) 
    {
        display_heading(sprintf(_("Allocated amounts in %s:"), $cart->person_curr));
        start_table(TABLESTYLE, "width='60%'");
           $th = array(_("Transaction Type"), _("#"), _("Branch"), $supp_ref ? _("Supplier Ref"): _("Ref"), _("Date"), _("Due Date"), _("Amount"),
               _("Other Allocations"), _("Left to Allocate"), _("This Allocation"),'',''); // added branch heading

           table_header($th);

        foreach ($cart->allocs as $id => $alloc_item)
        {
            if (floatcmp(abs($alloc_item->amount), $alloc_item->amount_allocated))
            {
                $myrow = get_customer_trans($alloc_item->type_no, ST_SALESINVOICE);// new to get trans data
                alt_table_row_color($k);
                label_cell($systypes_array[$alloc_item->type]);
                   label_cell(get_trans_view_str($alloc_item->type, $alloc_item->type_no), "nowrap align='right'");
                   label_cell($myrow['br_name'], "nowrap align='right'"); // to output branch
                   label_cell($alloc_item->ref);
                label_cell($alloc_item->date_, "align=right");
                label_cell($alloc_item->due_date, "align=right");
                amount_cell(abs($alloc_item->amount));
                amount_cell($alloc_item->amount_allocated);

                $_POST['amount' . $id] = price_format($alloc_item->current_allocated);

                $un_allocated = round((abs($alloc_item->amount) - $alloc_item->amount_allocated), 6);
                amount_cell($un_allocated, false,'', 'maxval'.$id);
                amount_cells(null, "amount" . $id);//, input_num('amount' . $id));
                label_cell("<a href='javascript:void(0)' name=Alloc$id onclick='allocate_all(this.name.substr(5));return true;'>"
                     . _("All") . "</a>");
                label_cell("<a href='javascript:void(0)' name=DeAll$id onclick='allocate_none(this.name.substr(5));return true;'>"
                     . _("None") . "</a>".hidden("un_allocated" . $id, 
                     price_format($un_allocated), false));
                end_row();

                   $total_allocated += input_num('amount' . $id);
               }
        }
        if ($show_totals) {
               label_row(_("Total Allocated"), price_format($total_allocated),
                "colspan=8 align=right", "align=right id='total_allocated'", 3);

            $amount = abs($cart->amount);

            if (floatcmp($amount, $total_allocated) < 0)
            {
                $font1 = "<font color=red>";
                $font2 = "</font>";
            }
            else
                $font1 = $font2 = "";
            $left_to_allocate = price_format($amount - $total_allocated);
            label_row(_("Left to Allocate"), $font1 . $left_to_allocate . $font2, 
                "colspan=8 align=right", "nowrap align=right id='left_to_allocate'",
                 3);
        }
        end_table(1);
    }
    hidden('TotalNumberOfAllocs', count($cart->allocs));
}

I will try to add logic to check the branch in the loop. if anyone good at this stuff can help lol
Thank you

Is it possible on the customer payments page show only the invoices by branch or at least have it show in the allocation table what branch the invoice belongs too. We have customers with over 800 branches and it is really difficult to find the correct invoice.

on this page
/sales/customer_payments.php

function in question
show_allocatable();
calls
class allocation
set_person()
read()

easy for invoices

reports_main.php                     (change the array)

$reports->addReport(RC_CUSTOMER, 107, _('Print &Invoices'),
    array(    //_('From') => 'INVOICE',       // removed for date
            //_('To') => 'INVOICE',         // removed for date  
            _('Start Date') => 'DATEBEGINM',    // added for date
            _('End Date') => 'DATEENDM',        // added for date
            _('Currency Filter') => 'CURRENCY',
            _('email Customers') => 'YES_NO',
            _('Payment Link') => 'PAYMENT_LINK',
            _('Comments') => 'TEXTBOX',
            _('Customer') => 'CUSTOMERS_NO_FILTER',
            _('Orientation') => 'ORIENTATION'
));

rep107.php         (change the function)

function get_invoice_range($from, $to, $currency=false)
{
    global $SysPrefs;
//--- new for date search instead of     
    $fromdate = date2sql($from);
    $todate = date2sql($to);
//---- End new stuff    


    $ref = ($SysPrefs->print_invoice_no() == 1 ? "trans_no" : "reference");

    $sql = "SELECT trans.trans_no, trans.reference";

//  if($currency !== false)
//        $sql .= ", cust.curr_code";

    $sql .= " FROM ".TB_PREF."debtor_trans trans 
            LEFT JOIN ".TB_PREF."voided voided ON trans.type=voided.type AND trans.trans_no=voided.id";

    if ($currency !== false)
        $sql .= " LEFT JOIN ".TB_PREF."debtors_master cust ON trans.debtor_no=cust.debtor_no";

    $sql .= " WHERE trans.type=".ST_SALESINVOICE
        ." AND ISNULL(voided.id)"
     //    ." AND trans.trans_no BETWEEN ".db_escape($from)." AND ".db_escape($to) //removed old
         ." AND trans.tran_date>='$fromdate'" // added this
        ." AND trans.tran_date<='$todate'";     //added this        

    if ($currency !== false)
        $sql .= " AND cust.curr_code=".db_escape($currency);

    $sql .= " ORDER BY trans.tran_date, trans.$ref";

    return db_query($sql, "Cant retrieve invoice range");
}

more difficult for deliveries

I find it hard to understand why the default reporting is by order created for invoices and delivery notes. Ok, maybe you go about your day entering some invoices then printing in batches. but couldn't you just click print right after creation if that is how you work?

Most people batch these things out by the day, most certainly deliveries. ie. You go about your work week or month scheduling deliveries to be efficient. then batch print all the delivery notes for the day. "Here you go Timmy here is your stops/deliveries for the day".

Then depending on what deliveries were completed you would invoice. so lets say Timmy comes back and didn't do some jobs. He gave you that reason about not feeling to good again. So you move the deliveries to a future date invoice the ones that were completed for the day and batch print or email them.

Maybe you mail invoices by date as well the whole month at once and make bills due on a date of the month. I can see many reasons why you would do date and not due order created.

What do you guys think?

61

(16 replies, posted in Wish List)

I agree with tm its what I did so you get the URL printed and the QR on the invoice

copy the library from here https://sourceforge.net/projects/phpqrc … t/download
to --> /reporting/includes/

in the file
/reporting/includes/doctext.inc

in the top

// add QR Support mod
    $path_to_root="..";
    include_once($path_to_root . "/reporting/includes/phpqrcode/qrlib.php");

    $tempDir = $path_to_root ."/company/1/pdf_files/"; // <--NOTE must be your temp location
// end

the if statement around line 270 should look like this

    if (@$this->formData['payment_service'])    //payment link
    {
        $amt = number_format($this->formData["ov_freight"] + $this->formData["ov_gst"] + $this->formData["ov_amount"], user_price_dec());
        $service = $this->formData['payment_service'];
        $url = payment_link($service, array(
            'company_email' => $this->company['email'],
            'amount' => $amt,
            'currency' => $this->formData['curr_code'],
            'comment' => $this->title . " " . $this->formData['reference'],
            'invoice' => $this->formData['document_number']
            ));
        $Footer[_("You can pay through"). " $service: "] = "$url";
// QR Mod
        $tempname = tempnam($tempDir,'QRcode');
        QRcode::png($url, $tempname.'.png', QR_ECLEVEL_L, 3);
        $this->Image($tempname.'.png',486,670,100,100);
// End
    }

Thank you, I ended up getting it working with the base fpdf built in function Image().
Now I just need to figure out where to put this thing. Haha it looks weird everywhere! I hate when things are not Symmetrical.

    if (@$this->formData['payment_service'])    //payment link
    {
        $amt = number_format($this->formData["ov_freight"] + $this->formData["ov_gst"] + $this->formData["ov_amount"], user_price_dec());
        $service = $this->formData['payment_service'];
        $url = payment_link($service, array(
            'company_email' => $this->company['email'],
            'amount' => $amt,
            'currency' => $this->formData['curr_code'],
            'comment' => $this->title . " " . $this->formData['reference'],
            'invoice' => $this->formData['reference']
            ));
        $Footer[_("You can pay through"). " $service: "] = "$url";
        QRcode::png($url, $tempDir.'030.png', QR_ECLEVEL_L, 3);
        $this->Image($tempDir.'030.png',35,540);
    }

I cant display a QR image in the Footer. I tried the $Footer[] array but I seams that It only displays text. I generate the QR from the URL in doctext.inc

 
    if (@$this->formData['payment_service'])    //payment link
    {
        $amt = number_format($this->formData["ov_freight"] + $this->formData["ov_gst"] + $this->formData["ov_amount"], user_price_dec());
        $service = $this->formData['payment_service'];
        $url = payment_link($service, array(
            'company_email' => $this->company['email'],
            'amount' => $amt,
            'currency' => $this->formData['curr_code'],
            'comment' => $this->title . " " . $this->formData['reference'],
            'invoice' => $this->formData['reference']
            ));
        $Footer[_("You can pay through"). " $service: "] = "$url";
        QRcode::png($url, $tempDir.'030.png', QR_ECLEVEL_L, 3);
    }

64

(1 replies, posted in Wish List)

We have an high interest bitcoin savings account that pays in bitcoin and have a few customers that pay in bitcoin. I would like to see better support for Bitcoin as a currency. As is the system works fine to account for as an asset (ie. capital gains or loss)

Bitcoin problems
1 The automatic get exchange rate does not function (but can be entered manually)
2 front accounting only supports one type of floating point number at a time. Can't have 2 decimal points "cents" for USD account and 8 decimal places for your BTC accounts. (That I know of) bit-cents are far to valueable already at 88 USD (My work around is to use the smallest value the Satoshis .00000001 BTC And disregarding the decimal place. Unfortunately, this could lead to many incorrect entries due to the strange nonstandard BTCformatting

Example .00432 BTC being entered as 432 Satoshi when it is 432000

BTC is gaining traction and I'm sure we will see much more in the coming years with the global recession.

Yes, unfortunately it shows voided invoices now Wished this could be removed and if you click the option to edit a voided it will throw a SQL error.

DATABASE ERROR : document version retreival
error code : 1064
error message : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 2
sql that failed was : SELECT trans_no, version FROM 2_debtor_trans WHERE type='13' AND ()

You  guys are awesome and that did work.

Just to let you know it still doesn't show the delivery notes in the 0.00 amount.

Thanks again, you guys are always the greatest

I just upgraded to 2.4.4 from 2.4.1 and it no longer shows sales invoices if they were for free i.e. 0.00

We create service invoices for 0.00 when work was guaranteed all the time and can no longer see the clients complete  work history.  The invoices can no longer be seen all types and I just noticed the delivery notes are missing as well.

Thank you

Sorry to delay on this response I've just been very busy.

I just wanted a question about the upgrade and this transaction.

Should I just do the update with the transaction how it is or should I void the transaction update then redo the transaction.

Basically, is it a problem how the transaction was written to the ledgers or just how it was interpreted / read from them.

Thank you.

Hello,

I have noticed if you debit a clients account receivables directly from a journal entry that there seems to be an error. when you check the client under Customer Transaction Inquiry all looks well but when creating a new invoice under Current Credit the calculation will be incorrect showing they have more credit available to them.

for Example

Sales Invoice    2/21/18 Debit 65.00
Sales Invoice  4/18/18 Debit 65.00
Customer Payment 4/20/18 Credit 65.00
Journal Entry 4/26/18 Debit 65.00 (Customer cheque was returned)

Client's balance should be 120.00 and it shows that in Customer Transaction Inquiry
but in enter direct invoice it shows 0.00 so it calculates the debit to A/R as a credit

70

(13 replies, posted in Reporting)

Ok here is a stock file with only the print invoice balance modifacations.

<?php
/**********************************************************************
    Copyright (C) FrontAccounting, LLC.
    Released under the terms of the GNU General Public License, GPL, 
    as published by the Free Software Foundation, either version 3 
    of the License, or (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
***********************************************************************/
$page_security = $_POST['PARAM_0'] == $_POST['PARAM_1'] ?
    'SA_SALESTRANSVIEW' : 'SA_SALESBULKREP';
// ----------------------------------------------------------------
// $ Revision:    2.0 $
// Creator:    Joe Hunt
// date_:    2005-05-19
// Title:    Print Invoices
// ----------------------------------------------------------------
$path_to_root="..";

include_once($path_to_root . "/includes/session.inc");
include_once($path_to_root . "/includes/date_functions.inc");
include_once($path_to_root . "/includes/data_checks.inc");
include_once($path_to_root . "/sales/includes/sales_db.inc");

//----------------------------------------------------------------------------------------------------
function get_invoice_range($from, $to)
{
    global $SysPrefs;

    $ref = ($SysPrefs->print_invoice_no() == 1 ? "trans_no" : "reference");

    $sql = "SELECT trans.trans_no, trans.reference
        FROM ".TB_PREF."debtor_trans trans 
            LEFT JOIN ".TB_PREF."voided voided ON trans.type=voided.type AND trans.trans_no=voided.id
        WHERE trans.type=".ST_SALESINVOICE
            ." AND ISNULL(voided.id)"
            ." AND trans.reference>=".db_escape(get_reference(ST_SALESINVOICE, $from))
            ." AND trans.reference<=".db_escape(get_reference(ST_SALESINVOICE, $to))
        ." ORDER BY trans.tran_date, trans.$ref";

    return db_query($sql, "Cant retrieve invoice range");
}

print_invoices();

//---------------------------------------------------------------------------------------------------- added from rep101 to get current balance


function get_open_balance($debtorno, $to)
{
    if($to)
        $to = date2sql($to);

     $sql = "SELECT SUM(IF(t.type = ".ST_SALESINVOICE." OR (t.type = ".ST_JOURNAL." AND t.ov_amount>0),
         -abs(t.ov_amount + t.ov_gst + t.ov_freight + t.ov_freight_tax + t.ov_discount), 0)) AS charges,";
     $sql .= "SUM(IF(t.type != ".ST_SALESINVOICE." AND NOT(t.type = ".ST_JOURNAL." AND t.ov_amount>0),
         abs(t.ov_amount + t.ov_gst + t.ov_freight + t.ov_freight_tax + t.ov_discount) * -1, 0)) AS credits,";
     $sql .= "SUM(IF(t.type != ".ST_SALESINVOICE." AND NOT(t.type = ".ST_JOURNAL." AND t.ov_amount>0), t.alloc * -1, t.alloc)) AS Allocated,";

     $sql .=    "SUM(IF(t.type = ".ST_SALESINVOICE.", 1, -1) *
             (abs(t.ov_amount + t.ov_gst + t.ov_freight + t.ov_freight_tax + t.ov_discount) - abs(t.alloc))) AS OutStanding
        FROM ".TB_PREF."debtor_trans t
        WHERE t.debtor_no = ".db_escape($debtorno)
        ." AND t.type <> ".ST_CUSTDELIVERY;
    if ($to)
        $sql .= " AND t.tran_date < '$to+1'"; // Has +1 to include any invoices created today in the balance
    $sql .= " GROUP BY debtor_no";

    $result = db_query($sql,"No transactions were returned");
    return db_fetch($result);
}


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

function print_invoices()
{
    global $path_to_root, $SysPrefs;
    
    $show_this_payment = true; // include payments invoiced here in summary

    include_once($path_to_root . "/reporting/includes/pdf_report.inc");

    $from = $_POST['PARAM_0'];
    $to = $_POST['PARAM_1'];
    $currency = $_POST['PARAM_2'];
    $email = $_POST['PARAM_3'];
    $pay_service = $_POST['PARAM_4'];
    $comments = $_POST['PARAM_5'];
    $customer = $_POST['PARAM_6'];
    $orientation = $_POST['PARAM_7'];

    if (!$from || !$to) return;

    $orientation = ($orientation ? 'L' : 'P');
    $dec = user_price_dec();

     $fno = explode("-", $from);
    $tno = explode("-", $to);
    $from = min($fno[0], $tno[0]);
    $to = max($fno[0], $tno[0]);

    //-------------code-Descr-Qty--uom--tax--prc--Disc-Tot--//
    $cols = array(4, 60, 225, 300, 325, 385, 450, 515);

    // $headers in doctext.inc
    $aligns = array('left',    'left',    'right', 'center', 'right', 'right', 'right');

    $params = array('comments' => $comments);

    $cur = get_company_Pref('curr_default');

    if ($email == 0)
        $rep = new FrontReport(_('INVOICE'), "InvoiceBulk", user_pagesize(), 9, $orientation);
    if ($orientation == 'L')
        recalculate_cols($cols);

    $range = get_invoice_range($from, $to);
    while($row = db_fetch($range))
    {
            if (!exists_customer_trans(ST_SALESINVOICE, $row['trans_no']))
                continue;
            $sign = 1;
            $myrow = get_customer_trans($row['trans_no'], ST_SALESINVOICE);

            if ($customer && $myrow['debtor_no'] != $customer) {
                continue;
            }
            if ($currency != ALL_TEXT && $myrow['curr_code'] != $currency) {
                continue;
            }
            $baccount = get_default_bank_account($myrow['curr_code']);
            $params['bankaccount'] = $baccount['id'];

            $branch = get_branch($myrow["branch_code"]);
            $sales_order = get_sales_order_header($myrow["order_"], ST_SALESORDER);
            if ($email == 1)
            {
                $rep = new FrontReport("", "", user_pagesize(), 9, $orientation);
                $rep->title = _('INVOICE');
                $rep->filename = "Invoice" . $myrow['reference'] . ".pdf";
            }    
            $rep->currency = $cur;
            $rep->Font();
            $rep->Info($params, $cols, null, $aligns);

            $contacts = get_branch_contacts($branch['branch_code'], 'invoice', $branch['debtor_no'], true);
            $baccount['payment_service'] = $pay_service;
            $rep->SetCommonData($myrow, $branch, $sales_order, $baccount, ST_SALESINVOICE, $contacts);
            $rep->SetHeaderType('Header2');
            $rep->NewPage();
            // calculate summary start row for later use
            $summary_start_row = $rep->bottomMargin + (15 * $rep->lineHeight);

            if ($rep->formData['prepaid'])
            {
                $result = get_sales_order_invoices($myrow['order_']);
                $prepayments = array();
                while($inv = db_fetch($result))
                {
                    $prepayments[] = $inv;
                    if ($inv['trans_no'] == $row['trans_no'])
                    break;
                }

                if (count($prepayments) > ($show_this_payment ? 0 : 1))
                    $summary_start_row += (count($prepayments)) * $rep->lineHeight;
                else
                    unset($prepayments);
            }

               $result = get_customer_trans_details(ST_SALESINVOICE, $row['trans_no']);
            $SubTotal = 0;
            while ($myrow2=db_fetch($result))
            {
                if ($myrow2["quantity"] == 0)
                    continue;

                $Net = round2($sign * ((1 - $myrow2["discount_percent"]) * $myrow2["unit_price"] * $myrow2["quantity"]),
                   user_price_dec());
                $SubTotal += $Net;
                $DisplayPrice = number_format2($myrow2["unit_price"],$dec);
                $DisplayQty = number_format2($sign*$myrow2["quantity"],get_qty_dec($myrow2['stock_id']));
                $DisplayNet = number_format2($Net,$dec);
                if ($myrow2["discount_percent"]==0)
                      $DisplayDiscount ="";
                else
                      $DisplayDiscount = number_format2($myrow2["discount_percent"]*100,user_percent_dec()) . "%";
                $c=0;
                $rep->TextCol($c++, $c,    $myrow2['stock_id'], -2);
                $oldrow = $rep->row;
                $rep->TextColLines($c++, $c, $myrow2['StockDescription'], -2);
                $newrow = $rep->row;
                $rep->row = $oldrow;
                if ($Net != 0.0 || !is_service($myrow2['mb_flag']) || !$SysPrefs->no_zero_lines_amount())
                {
                    $rep->TextCol($c++, $c,    $DisplayQty, -2);
                    $rep->TextCol($c++, $c,    $myrow2['units'], -2);
                    $rep->TextCol($c++, $c,    $DisplayPrice, -2);
                    $rep->TextCol($c++, $c,    $DisplayDiscount, -2);
                    $rep->TextCol($c++, $c,    $DisplayNet, -2);
                }
                $rep->row = $newrow;
                //$rep->NewLine(1);
                if ($rep->row < $summary_start_row)
                    $rep->NewPage();
            }

            $memo = get_comments_string(ST_SALESINVOICE, $row['trans_no']);
            if ($memo != "")
            {
                $rep->NewLine();
                $rep->TextColLines(1, 3, $memo, -2);
            }

               $DisplaySubTot = number_format2($SubTotal,$dec);

            // set to start of summary line:
            $rep->row = $summary_start_row;
            if (isset($prepayments))
            {
                // Partial invoices table
                $rep->TextCol(0, 3,_("Prepayments invoiced to this order up to day:"));
                $rep->TextCol(0, 3,    str_pad('', 150, '_'));
                $rep->cols[2] -= 20;
                $rep->aligns[2] = 'right';
                $rep->NewLine(); $c = 0; $tot_pym=0;
                $rep->TextCol(0, 3,    str_pad('', 150, '_'));
                $rep->TextCol($c++, $c, _("Date"));
                $rep->TextCol($c++, $c,    _("Invoice reference"));
                $rep->TextCol($c++, $c,    _("Amount"));

                foreach ($prepayments as $invoice)
                {
                    if ($show_this_payment || ($invoice['reference'] != $myrow['reference']))
                    {
                        $rep->NewLine();
                        $c = 0; $tot_pym += $invoice['prep_amount'];
                        $rep->TextCol($c++, $c,    sql2date($invoice['tran_date']));
                        $rep->TextCol($c++, $c,    $invoice['reference']);
                        $rep->TextCol($c++, $c, number_format2($invoice['prep_amount'], $dec));
                    }
                    if ($invoice['reference']==$myrow['reference']) break;
                }
                $rep->TextCol(0, 3,    str_pad('', 150, '_'));
                $rep->NewLine();
                $rep->TextCol(1, 2,    _("Total payments:"));
                $rep->TextCol(2, 3,    number_format2($tot_pym, $dec));
            }


            $doctype = ST_SALESINVOICE;
            $rep->row = $summary_start_row;
            $rep->cols[2] += 20;
            $rep->cols[3] += 20;
            $rep->aligns[3] = 'left';

            $rep->TextCol(3, 6, _("Sub-total"), -2);
            $rep->TextCol(6, 7,    $DisplaySubTot, -2);
            $rep->NewLine();
            if ($myrow['ov_freight'] != 0.0)
            {
                   $DisplayFreight = number_format2($sign*$myrow["ov_freight"],$dec);
                $rep->TextCol(3, 6, _("Shipping"), -2);
                $rep->TextCol(6, 7,    $DisplayFreight, -2);
                $rep->NewLine();
            }    
            $tax_items = get_trans_tax_details(ST_SALESINVOICE, $row['trans_no']);
            $first = true;
            while ($tax_item = db_fetch($tax_items))
            {
                if ($tax_item['amount'] == 0)
                    continue;
                $DisplayTax = number_format2($sign*$tax_item['amount'], $dec);

                if ($SysPrefs->suppress_tax_rates() == 1)
                    $tax_type_name = $tax_item['tax_type_name'];
                else
                    $tax_type_name = $tax_item['tax_type_name']." (".$tax_item['rate']."%) ";

                if ($myrow['tax_included'])
                {
                    if ($SysPrefs->alternative_tax_include_on_docs() == 1)
                    {
                        if ($first)
                        {
                            $rep->TextCol(3, 6, _("Total Tax Excluded"), -2);
                            $rep->TextCol(6, 7,    number_format2($sign*$tax_item['net_amount'], $dec), -2);
                            $rep->NewLine();
                        }
                        $rep->TextCol(3, 6, $tax_type_name, -2);
                        $rep->TextCol(6, 7,    $DisplayTax, -2);
                        $first = false;
                    }
                    else
                        $rep->TextCol(3, 6, _("Included") . " " . $tax_type_name . _("Amount") . ": " . $DisplayTax, -2);
                }
                else
                {
                    $rep->TextCol(3, 6, $tax_type_name, -2);
                    $rep->TextCol(6, 7,    $DisplayTax, -2);
                }
                $rep->NewLine();
            }

            $rep->NewLine();

//-----------------------------------------------------------added to fetch and calculate total balance
                $accumulate = 0;                    
                $bal = get_open_balance($myrow['debtor_no'],today()); 
                $init[0] = $init[1] = 0.0;
            $init[0] = round2(abs($bal['charges']), $dec);
            $init[1] = round2(Abs($bal['credits']), $dec);
            $init[2] = round2($bal['Allocated'], $dec);
            $init[3] = $init[0] - $init[1];
            $accumulate += $init[3];
//-----------------------------------------------------------End added to fetch and calculate total balance

            $DisplayTotal = number_format2($sign*($myrow["ov_freight"] + $myrow["ov_gst"] +
                $myrow["ov_amount"]+$myrow["ov_freight_tax"]),$dec);
            $rep->Font('bold');
            if (!$myrow['prepaid']) $rep->Font('bold');
                $rep->TextCol(3, 6, $rep->formData['prepaid'] ? _("TOTAL ORDER VAT INCL.") : _("TOTAL INVOICE"), - 2);
            $rep->TextCol(6, 7, $DisplayTotal, -2);

//-------------------------------------------- added to display total balance            
            $rep->NewLine(); 
            $rep->TextCol(3, 6, $rep->formData['prepaid'] ? _("TOTAL ORDER VAT INCL.") : _("TOTAL BALANCE"), - 2); 
            $DisplayGrand = number_format2($init[3],$dec);
            $rep->TextCol(6, 7, $DisplayGrand, -2); 
//-----------------------------------------------------------End added to display total balance    

            if ($rep->formData['prepaid'])
            {
                $rep->NewLine();
                $rep->Font('bold');
                $rep->TextCol(3, 6, $rep->formData['prepaid']=='final' ? _("THIS INVOICE") : _("TOTAL INVOICE"), - 2);
                $rep->TextCol(6, 7, number_format2($myrow['prep_amount'], $dec), -2);
            }
            $words = price_in_words($rep->formData['prepaid'] ? $myrow['prep_amount'] : $myrow['Total']
                , array( 'type' => ST_SALESINVOICE, 'currency' => $myrow['curr_code']));
            if ($words != "")
            {
                $rep->NewLine(1);
                $rep->TextCol(1, 7, $myrow['curr_code'] . ": " . $words, - 2);
            }
            $rep->Font();
            if ($email == 1)
            {
                $rep->End($email);
            }
    }
    if ($email == 0)
        $rep->End();
}

I was pretty busy with work.

Update, I have used it this way for a week with no problems. It works much better.

72

(13 replies, posted in Reporting)

@Apmuthu

Ok I got it working Thank You for the help. I'll send you some money on Pay Pal for your help on Monday (Waiting to verify the new Bank Account) I'll send it to the Email on you whois for the domain.

So, Here is the code for anyone that wants it. I am no coder so someone might want to clean it up, but it works.
It will print the clients current balance for all invoices up to the day it s printed. For example if today is 1/12/18 it will includeinvoices with dates from 1/5/18 and 1/12/18 but not an invoice made for the future 1/16/18.

add this funcion from rep101.php to the top of your /reporting/rep107.php where all the funcions are

function get_open_balance($debtorno, $to)
{
    if($to)
        $to = date2sql($to);

     $sql = "SELECT SUM(IF(t.type = ".ST_SALESINVOICE." OR (t.type = ".ST_JOURNAL." AND t.ov_amount>0),
         -abs(t.ov_amount + t.ov_gst + t.ov_freight + t.ov_freight_tax + t.ov_discount), 0)) AS charges,";
     $sql .= "SUM(IF(t.type != ".ST_SALESINVOICE." AND NOT(t.type = ".ST_JOURNAL." AND t.ov_amount>0),
         abs(t.ov_amount + t.ov_gst + t.ov_freight + t.ov_freight_tax + t.ov_discount) * -1, 0)) AS credits,";
     $sql .= "SUM(IF(t.type != ".ST_SALESINVOICE." AND NOT(t.type = ".ST_JOURNAL." AND t.ov_amount>0), t.alloc * -1, t.alloc)) AS Allocated,";

     $sql .=    "SUM(IF(t.type = ".ST_SALESINVOICE.", 1, -1) *
             (abs(t.ov_amount + t.ov_gst + t.ov_freight + t.ov_freight_tax + t.ov_discount) - abs(t.alloc))) AS OutStanding
        FROM ".TB_PREF."debtor_trans t
        WHERE t.debtor_no = ".db_escape($debtorno)
        ." AND t.type <> ".ST_CUSTDELIVERY;
    if ($to)
        $sql .= " AND t.tran_date < '$to+1'";
    $sql .= " GROUP BY debtor_no";

    $result = db_query($sql,"No transactions were returned");
    return db_fetch($result);
}

Then add this above

                        $accumulate = 0;                    
                $bal = get_open_balance($myrow['debtor_no'],today()); 
                $init[0] = $init[1] = 0.0;
            $init[0] = round2(abs($bal['charges']), $dec);
            $init[1] = round2(Abs($bal['credits']), $dec);
            $init[2] = round2($bal['Allocated'], $dec);
            $init[3] = $init[0] - $init[1];
            $accumulate += $init[3];

and this below

$rep->TextCol(6, 7, $DisplayTotal, -2);
            $rep->NewLine(); // added for total balance
            $rep->TextCol(3, 6, $rep->formData['prepaid'] ? _("TOTAL ORDER VAT INCL.") : _("TOTAL BALANCE"), - 2); 
            $DisplayGrand = number_format2($init[3],$dec);
            $rep->TextCol(6, 7, $DisplayGrand, -2); // added for total balance

This line of code

            $DisplayTotal = number_format2($sign*($myrow["ov_freight"] + $myrow["ov_gst"] +
                $myrow["ov_amount"]+$myrow["ov_freight_tax"]),$dec);
            $rep->Font('bold');
            if (!$myrow['prepaid']) $rep->Font('bold');
                $rep->TextCol(3, 6, $rep->formData['prepaid'] ? _("TOTAL ORDER VAT INCL.") : _("THIS INVOICE"), - 2);

73

(3 replies, posted in Report Bugs here)

Okay I was a complete fool it wasn't working because I was entering the payment in the bank charges section. Thats why I couldnt allocate because there was no balance left to allocate. There could be a if statement to prevent that. I feel like a fool. Ha

74

(3 replies, posted in Report Bugs here)

Okay I was able to fix the debit account to be undeposited funds that setting was actually under the bank account setting but I still can't allocate a payment to an invoice

75

(3 replies, posted in Report Bugs here)

Ok, I also get that error when allocating in the Customer Payment Entry ui as well.

I can see the amount was credited from accounts receivables and debited in 5690 Interest & Bank Charges???

shouldn't it go to a undeposited funds account in current assets???

Thanks