A fully working non-composer-ised version of the Slim2 REST Framework customised for FA 2.4.x is now available.

@joe: Attachements don't work for this version of the forum as yet.- Now done.

2,352

(86 replies, posted in Modules Add-on's)

Here are some quaint errors:

0::Set.php:72:[before upgrade] Redefining already defined constructor for class Slim\Helper\Set

0::Log.php:304:[before upgrade] Redefining already defined constructor for class Slim\Log

Whilst the Slim framework files use the newer function __construct(), the presence of function names (even if case is different) bearing the class name will be construed as being a re-declaration of the class constructor!. See Set.php and Log.php for functions set() and log() respectively atleast in earlier versions of PHP like 5.3.1. Renaming the class file names and their class names like WSet and WLog and altering them in files they are used alleviates these errors.

Line 163 of vendor/slim/slim/Slim/Helper/Set.php should not have any return value.

Line 309 of vendor/slim/slim/Slim/Log.php simply returns the string value even if it is an passed to it. In it's earlier avatar, it was replaced by:

            if (is_array($object) || (is_object($object) && !method_exists($object, "__toString"))) {
                $message = print_r($object, true);
            } else {
                $message = (string) $object;
            }

Is line 111 of vendor/slim/slim/Slim/View.php okay?
Should Closure be preceded by a slash?

Line 18 of src/Purchases.php should be like all the others:

$body = array();

@joe / @itronics:

From the PHP Manual Comments:

Using the 'set_exception_handler' function within a class, the defined 'exception_handler' method must be declared as 'public' (preferrable 'public static' if you use the "array('example', 'exception_handler')" syntax). It should be in an array as below:

<?php
class example {
    public function __construct() {
        @set_exception_handler(array('example', 'exception_handler'));
        throw new Exception('DOH!!');
    }

    public static function exception_handler($exception) {
        print "Exception Caught: ". $exception->getMessage() ."\n";
    }
}

$example = new example;

echo "Not Executed\n";
?>

Declaring the 'exception_handler' function as 'private' causes a FATAL ERROR.

Looks like every instance of exception handling within a class should be so coded for PHP 5.6 / 7.1.

Place the 3 files one by one and see which one is faulty.

I am unable to simulate your error. Please state what steps were necessary to trigger it. Make sure your tmp folder is writeable by your webserver process.

2,355

(86 replies, posted in Modules Add-on's)

Make the session_utils.inc file part of the API code. Will test and let you know.

Yes.

@itronics: please commit fixes in post #6 here.

There are 2 corrections in my post above.

The function exception_handler() is defined in includes/errors.inc file and is included in line 372 (before function usage) in includes/session.inc. So all are okay here.

Typo  - missing comma - in commit.

Alter line 76 in the file sales/includes/db/sales_delivery_db.inc:

            $delivery_line->price*$qty, 0, $delivery->tax_included

to:

            $delivery_line->price*$qty, 0, $delivery->tax_included,

Also terminate line 80 with a semicolon.

@itronics: please commit it.
@Alaa: Nice catch.

2,359

(86 replies, posted in Modules Add-on's)

@cambell: please provide one that is stripped of composer and unit tests so that the end user can deploy and extend without a steep learning / confusing curve. As Slim v2.x can be used without composer by using it's internal AutoLoad feature, all vendor dependencies can be eliminated.

Your release does not work.

You have removed the class SessionManager() in the session-custom.php (not updated to reflect this core commit) but referred to it in the code at line 46.

Also you are referring to a hardcoded non-existent file/folder name in the config_api.php file: _frontaccounting

You are referring to $rootPath but have initialised $rootpath in config_api.php - in fact it is sufficient for it to have just:

define('API_ROOT', '.');
define('FA_ROOT', './../..');

irrespective of whether it is hosted on Windows or on Linux to alleviate the effect of the DIRECTORY_SEPARATOR.

You will want to add in the following into an .htaccess file:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]

Your api module just does not work. Tested in FA 2.4.3+, PHP 5.3.1.

So now we will have it uniformly as 11.905 in both Sales Delivery and Sales Invoice!

A search for the string "FIXME" in the entire codebase will popup several files!

2,361

(86 replies, posted in Modules Add-on's)

A tutorial on Slim REST API in general is attached.

@joe: Committed

2,363

(86 replies, posted in Modules Add-on's)

To get you started with Slim for FA, unzip the contents of the attachment in a folder called api under the FA modules folder, modify the URL shortcuts to suit your install and check it out. It has been hard coded for Company 1 with table prefix "1_".

Missing fields, field type definitions and sizes and order of fields, missing tables, presence of obsolete tables, etc.
Use WinMerge to compare.

Alternatively, load both original schemas without their data into two separate databases and do a schema compare possibly in SQLyog / phpMyAdmin or any other online tool that compares schemas - some listed in this forum as well.

The easiest way forward is to use the sql/en_US-new.sql Chart and then alter what you want to suit AU requirements.

Take a backup of your database and compare the schema with the sql/en_US-new.sql and see if the missing fields / tables are in place. Which Chart of Accounts did you start with - AU general or AU service? The latter is  quite modified in terms of the table data but they both have similar schemas.

The function write_customer_trans_detail_item($debtor_trans_type, $debtor_trans_no, $stock_id, $description, $quantity, $unit_price, $unit_tax, $discount_percent, $std_cost, $src_id, $line_id=0) is defined in sales/includes/db/cust_trans_details_db.inc.

When creating the Sales Delivery, the working lines 71-88 of sales/includes/db/sales_delivery_db.inc are:

    foreach ($delivery->line_items as $line_no => $delivery_line) {

        $line_price = $delivery_line->line_price();
        $line_taxfree_price = get_tax_free_price_for_item($delivery_line->stock_id,
            $delivery_line->price, 0, $delivery->tax_included,
            $delivery->tax_group_array);

        $line_tax = get_full_price_for_item($delivery_line->stock_id, $delivery_line->price,
            0, $delivery->tax_included, $delivery->tax_group_array) - $line_taxfree_price;

        $delivery_line->standard_cost = get_unit_cost($delivery_line->stock_id);

        /* add delivery details for all lines */
        write_customer_trans_detail_item(ST_CUSTDELIVERY, $delivery_no, $delivery_line->stock_id,
            $delivery_line->item_description, $delivery_line->qty_dispatched,
            $delivery_line->line_price(), $line_tax,
            $delivery_line->discount_percent, $delivery_line->standard_cost, $delivery_line->src_id,
            $trans_no ? $delivery_line->id : 0);

When creating the Sales Invoice, the corresponding working lines 105-119 of sales/includes/db/sales_invoice_db.inc are:

    foreach ($invoice->line_items as $line_no => $invoice_line) {
        $qty = $invoice_line->qty_dispatched;
        $line_taxfree_price = get_tax_free_price_for_item($invoice_line->stock_id,
            $invoice_line->price * $qty, 0, $invoice->tax_included,
            $invoice->tax_group_array);

        $line_tax = get_full_price_for_item($invoice_line->stock_id,
            $invoice_line->price * $qty, 0, $invoice->tax_included,
            $invoice->tax_group_array) - $line_taxfree_price;

        write_customer_trans_detail_item(ST_SALESINVOICE, $invoice_no, $invoice_line->stock_id,
            $invoice_line->item_description, $invoice_line->qty_dispatched,
            $invoice_line->line_price(), $qty ? $line_tax/$qty : 0, $invoice_line->discount_percent,
            $invoice_line->standard_cost, $invoice_line->src_id,
            $trans_no ? $invoice_line->id : 0);

Observe that the former is just a number whilst the latter is the result of a division by quantity if it exists. The latter results in some rounding off errors. Can the invoice not just be the unit tax as in the sales order? The element in question is in the  7th parameter in the call to the function write_customer_trans_detail_item() in each case.

The sql for the sales order is:

INSERT INTO `1_debtor_trans_details` VALUES
('13', '5', '13', '102', 'iPhone 6 64GB', '250', '11.9', '2', '0', '150', '2', '11'),

whilst that for the sales invoice is:

INSERT INTO `1_debtor_trans_details` VALUES
('15', '5', '10', '102', 'iPhone 6 64GB', '250', '11.905', '2', '0', '150', '0', '13'),

Note the difference:11.9 and 11.905 for unit_tax.

@joe: does this need fixing?

Setup => Company Setup => Active Financial year => choose the previous fiscal year. When making an entry for the previous financial year make sure the transaction date is in the previous financial year. If some core settings / permissions change in a session, logout, clear cache and login again.

2,368

(86 replies, posted in Modules Add-on's)

FA 2.3.x has a restful API developed by diaz. Search the wiki and the forum for it. Please note that the $unit_tax sent to Sales order is a proper number whilst that sent to the invoice is the result of a division by quantity yielding some irrational number in some instances.

Every transaction in FA can be deduced by comparing the backups of the database before and after the transaction and sifting the differences as I have done in the anatomy case above.

2,369

(86 replies, posted in Modules Add-on's)

All normal modules rely on the authenticated logged in session already existing within FA.

Creating a new API module will entail the creation of a session from within it as the end user will be another application server or one whose web authenticated session would not be available at the time of use.

We can however use cURL to "Log in" to FA from within the API to provide for a simulation of an authorised session while the API does it's work. Such requests will expose the credentials in plain text if the normal GET REST method is used or any other method in plain HTTP mode without suitable variable one time hashing.

@joe: Any standard construct to use the current_user::login($company, $username, $password) method in standalone mode without dependencies or listed dependencies for pre-inclusion since the $_SESSION['wa_current_user'] would not be normally available to start with?

2,370

(86 replies, posted in Modules Add-on's)

Use Firebug in Firefox. Choose to submit an FA Form to a dummy POST page ( <?php echo print_r($_POST, true); ?> ) that will display the parameters and form values.

Attached is the set of SQLs that get executed for a Direct Sales Invoice being entered from the Web UI. There is a split up of the sqls into a Sales Order, a Delivery, An Invoice and a Customer Payment for the same - all of which makes for a Direct Cash Sales Invoice.

2,371

(86 replies, posted in Modules Add-on's)

The Slim 2.x framework with some examples are provided along with links in the hello.php file in the attachment.

2,372

(2 replies, posted in Installation)

Security.

Reported in the Mantis BugTracker as issue #4082.

On a fresh install of FA 2.4.3 on WinXPSP3/XAMPP 1.73/PHP 5.3.1, we find that the "@" prefixing some function calls do not supress errors in the FA /tmp/errors.log. Here are a few errors that arose:

session.inc:440:[before upgrade] include_once(./tmp/faillog.php) [<a href='function.include-once'>function.include-once</a>]: failed to open stream: No such file or directory
session.inc:440:[before upgrade] include_once() [<a href='function.include'>function.include</a>]: Failed opening './tmp/faillog.php' for inclusion (include_path='.;\XAMPP\php\PEAR')
session.inc:490:[before upgrade] include(./company/0/installed_extensions.php) [<a href='function.include'>function.include</a>]: failed to open stream: No such file or directory
session.inc:490:[before upgrade] include() [<a href='function.include'>function.include</a>]: Failed opening './company/0/installed_extensions.php' for inclusion (include_path='.;\XAMPP\php\PEAR)
hooks.inc:238:[before upgrade] Invalid argument supplied for foreach()
current_user.inc:735:[before upgrade] opendir(./company/0/js_cache/0) [<a href='function.opendir'>function.opendir</a>]: failed to open dir: No such file or directory
session.inc:440:[before upgrade] include_once(./tmp/faillog.php) [<a href='function.include-once'>function.include-once</a>]: failed to open stream: No such file or directory
session.inc:440:[before upgrade] include_once() [<a href='function.include'>function.include</a>]: Failed opening './tmp/faillog.php' for inclusion (include_path='.;\XAMPP\php\PEAR')

Each time we logout of FA, the following gets logged (date/time prefix removed) in the FA /tmp/errors.log:

logout.php:50:[before upgrade] session_destroy() [<a href='function.session-destroy'>function.session-destroy</a>]: Session object destruction failed

These entries are the result of failure to respect the "@" prefixing the session_destroy() function used therein. Such entries, however, can be leveraged by any log parsing program to monitor logout events.

Just checked all instances of the check_db_has_XXXX() usage in such files  - they are all called after the page() call. It is also so in FA 2.3. Wonder what prompted the change in FA 2.4 to error out thus.

@notrinos: nice eagle eye!
@joe: Thanks for the clarifications.

Isn't it better to implement it likecheck_db_has_customers()inincludes/data_checks.incand as used insales/customer_payments.phpandsales/manage/customer_branches.php? That is how it is now after the commit!