51

(40 replies, posted in Reporting)

FA email is officially broken in PHP 8+ without mods, Gmail  and other mail server accounts are getting way stricter about delivery from mail(). We were getting client complaints. I think it's time to drop mail() and use phpmailer. The SMTP mail extension using phpmailer still works like a charm even in 8+ why not just include it in core? It is GNU LGPL 2.1

OK, It is all set to go there are two branches of route_deliveries

https://github.com/trafficpest/FA24extensions/tree/route_deliveries_no_ship
This works with current version of FA it has no shipper(driver) filter option available

https://github.com/trafficpest/FA24extensions/tree/route_deliveries
This version has a shipper filter by using adding an argument to a core FA function. The core change is below

https://github.com/trafficpest/FA/tree/shippers_branch
This is FA with the small function addition to filter shippers

Thank you hope this will be of use for others especially service industries

Sorry about the end if I was going to make a if statement if the table exists not to drop but to alter. But didn't get around to it.

Don't merge the route delivery plug in from my git yet.yesterday I corrected one bug and added a feature. I'll post here when it is pushed.

@Poncho I didn't know branches were optional that's a good heads up. Thank you for the plug-in it got my routing software going really easy. I needed branches to be able to support customers with multiple delivery locations. It now is routing and putting in order a hundred slips in an instant. This will save considerable time daily!

I just noticed in the include customer reporting Excel report the join has to be with branch code now to prevent branch duplicates in the query.

The Customer Additional Information screen requires a customer and branch to be set to add, update, or delete additional fields.

***Warning read the readme*** Prior to using id you already have an addfields_cust table in your database

repo is here git branch is additional_fields_w/branches
https://github.com/trafficpest/FA24extensions/tree/additional_fields_w/branches
https://github.com/trafficpest/FA24extensions/tree/master/Extensions/additional_fields

A new column `cust_branch_no` as 2nd primary key, was added to addfields_cust . I created new functions maintaining the old. I wasn't sure how the author @poncho wanted to go with it.

you could allow null in branch_no but I dont see why since FA creates a branch when you create a customer automatically.
You could use the `all branches` option. copy the add_field info to all branches in the customer you are working on.

I needed branches for the route_delivery extension I made. I have a few clients that have multiple delivery locations, under one account (branches)

55

(2 replies, posted in Wish List)

You should consider something else for point of sale and  connect it to your front accounting for full featured accounting. You could consider woocommerce or open cart for open and just have it on a tablet connected to wifi.

# README.md

## Dependencies
This plugin relies on the Additional Fields module to function. Please ensure 
it is installed before use.

## Installation
1. Unzip the files into your FrontAccounting modules directory, or
   Install it directly from the repository on FrontAccounting (if available).
2. In FrontAccounting, activate it in `Install/Active Extensions` under the 
   `Setup` tab.
3. If needed change the `access setup` to use reports.


## Usage
To use this plugin:
1. Add geocodes for clients as an additional field. 
- These geocodes should be set as long,lat (default) or lat,long format. 
  Example: -118.265376,34.376487
- For minimum accuracy, use GPS coordinates with at least 4 decimal places. 
  The industry standard is 6 decimal places, allowing accuracy within 4 square 
  inches on Earth. Avoid using more than 6 places to accommodate location 
  variations when the API calls OSRM. 
2. Run the new report `Route Deliveries` under `Customer` class in `reports`  
- By default, this plugin utilizes the public instance of OSRM, which may have 
data limitations. You can use your own instance if desired.

## Configuration (Config File)
You can adjust more permanent plugin options in the `route_config.php` file 
located in the root of the `rep_route_deliveries` directory. 
The Available options there are:

### field_label
Your custom label name in the FrontAccounting additional_fields extention where 
the GPS data is stored. The Default is 'Geocoding'.

### swap_cords
By default, OSRM expects GPS data in Long,Lat format. Set this to true if your 
data is in Lat,Long format, and the software will swap it accordingly. Ensure 
there are no spaces in your coordinates.

### home_point
GPS location to add to the start of your route. This location MUST be in 
Long,Lat order.

### osrm_url
The API URL of the OSRM instance used for routing data. Replace it with another 
URL if desired. Self hosted has no limits on request size and options.

### km
Set this to true to get kilometers. The default is miles

## Configuration (In App)

### Route Deliveries
With this it turns the routing function on, adds a route log to your report, 
and sorts the delivery slips in route order for you. This report does allow 
print by date that front accounting lacks by default.

### Remove Home Location
Remove the home_point location from the routing. Useful for starting at first 
delivery location.

### Route Linear, Not Roundtrip
By default, the route will be a round trip starting from the home_point or the 
first delivery stop. Set this to generate a route from the first stop 
(oldest delivery) to the last stop (newest).

## Known Limitations
- `additional fields` does not have branch support, So Only one geocode per 
client. If you have clients with more than one branch ie location they should be 
seperated.
- Only one trip is supported, the locations have to connect by roadway. You 
couldnt route deliveries in france and england at the same time.
- Doesn't support Shippers ie. Drivers. FrontAcconting core needs a small change 
I have submitted to the github mirror repo
- Doesn't support more than one shipping location (home point) This would be 
nice to add.

Ok, Sounds good. I wanted to make something that uses your own client geocode data (for accuracy) rather than trying to geocode from an address (rarely works, few free data sources,multiple regions, etc)

For the USA there is a Government data that is good found here
https://geocoding.geo.census.gov/geocoder/

The route delivery extension could have the option of sorting by delivery driver (shipper branch) if this core commit is added (it adds shipper_filter and add get_shipper function args)
https://github.com/trafficpest/FA/tree/shippers_branch

Ill post the readme here it has all the info need to get going and what it can do / options
I have the instance going for you to test. but I can not post the credentials publicly. It has clients data.
let me know if you would like me to email you.

Trying to make FA a little more delivery friendly. Fork is below, branch is shipper_branch. I created a pull request on the github mirror repo. I wanted to add routing for the report with Open street maps project but it needs geocoding of the addresses ie. customer custom field so, I will make that part a module.

https://github.com/trafficpest/FA

59

(57 replies, posted in Installation)

Looks like the repo is down, I cant access it in the web browser either.

StrikeOut has since been worked on and now has a modular payment system. New Payment Methods have been added.

PayPal (includes Venmo, credit cards when applicable)
LNbits Method to receive bitcoin lightning directly.

I have now included a very slightly modified version of frontaccounting that generates Static QR codes on the invoices if you chose StrikeOut as payment link. unfortunately the wiki is a little behind

there is a demo running with a sandboxed paypal and strike module running at

https://btspec.org

note: take care when using LNbits with the frontaccounting module since you invoice in your home currency but the receiving currency is actual bitcoin. You will have to make a bank acct in bitcoin sats. It is not appropriate accounting in most jurisdictions since it is usually treated as property not currency. I will update the front accounting plugin to treat it as inventory and enter the cost basis at the time of payment (the invoice amount).

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

62

(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?

71

(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);
    }

74

(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 ()