. ***********************************************************************/ // // FrontAccounting extension modules integration. // This file is included in session.inc even before session is started, // and includes hooks.php connector files from all installed extensions. // To make hooks active install_hooks() have to be called after interface // language is set. // // To find how various hooks are processed look into respective hook_* functions below. // class hooks { var $module_name; // extension module name. // // Helper for updating databases with extension scheme // // $comp can be company number, -1 for all, // $updates - table of filename => array(table, field, property) // $check_only - don't update database, check table/field/property existence only // function update_databases($comp, $updates, $check_only=false) { global $db_connections, $path_to_root; if ($comp == -1) $conn = $db_connections; else $conn = array( $comp => $db_connections[$comp]); $result = true; foreach($conn as $comp => $con) { set_global_connection($comp); foreach($updates as $file => $update) { $table = @$update[0]; $field = @$update[1]; $properties = @$update[2]; $ok = check_table($con['tbpref'], $table, $field, $properties) == 0; if (!$check_only && !$ok) { $ok = db_import($path_to_root.'/modules/'.$this->module_name.'/sql/'.$file, $con); } $result &= $ok; if (!$result) break; } db_close(); if (!$result) break; } set_global_connection(0); // return to siteadmin account return $result; } // // Install additional tabs provided by extension // function install_tabs($app) { // $app->add_application(new example_class); // add menu tab defined by example_class } // // Install additonal menu options provided by extension // function install_options($app) { // global $path_to_root; // // switch($app->id) { // case 'orders': // $app->add_rapp_function( 0, _("&Example option"), // $path_to_root.'/modules/example/example.php?', 'SA_OPEN'); // } } function install_access() { // $security_areas['SA_EXAMPLE'] = array(SS_EXAMPLE|100, _("Example security area.")); // // $security_sections = array(SS_EXAMPLE => _("Example module implementation")); // // return array($security_areas, $security_sections); } // // Invoked for all modules before page header is displayed // function pre_header($fun_args) { } // // Invoked for all modules before page footer is displayed // function pre_footer($fun_args) { } // // Price in words. $doc_type is set to document type and can be used to suppress // price in words printing for selected document types. // Used instead of built in simple english price_in_words() function. // // Returns: amount in words as string. function price_in_words($amount, $doc_type) { } // // Exchange rate currency $curr as on date $date. // Keep in mind FA has internally implemented 3 exrate providers // If any of them supports your currency, you can simply use function below // with apprioprate provider set, otherwise implement your own. // Returns: $curr value in home currency units as a real number. function retrieve_exrate($curr, $date) { // $provider = 'ECB'; // 'ECB', 'YAHOO' or 'GOOGLE' // return get_extern_rate($curr, $provider, $date); return null; } // External authentication // If used should return true after successfull athentication, false otherwise. function authenticate($login, $password) { return null; } // Generic function called at the end of Tax Report (report 709) // Can be used e.g. for special database updates on every report printing // or to print special tax report footer // // Returns: nothing function tax_report_done() { } // Following database transaction hooks akcepts array of parameters: // 'cart' => transaction data // 'trans_type' => transaction type function db_prewrite(&$cart, $trans_type) { return true; } function db_postwrite(&$cart, $trans_type) { return true; } function db_prevoid($trans_type, $trans_no) { return true; } /* This method is called after module install. */ function install_extension($check_only=true) { return true; } /* This method is called after module uninstall. */ function uninstall_extension($check_only=true) { return true; } /* This method is called on extension activation for company. */ function activate_extension($company, $check_only=true) { return true; } /* This method is called when extension is deactivated for company. */ function deactivate_extension($company, $check_only=true) { return true; } /* * Returns the quantity allowed to be dispatched for a particular item * and a status (which can be used to style the row). * This quantity would be the default value on the delivery note. * The usual use case for this is when a item is in stock, * but has been reserved by someone else. * This allows extensions to implements its own priority algorithm. * This function is by detail_id and not item in case the item is present * more than one in the cart. */ /* Default behavior check if there is enough quantity on hand and change the css * class if needed */ static function default_get_dispatchable_quantity($line_item, $location, $date, $qoh) { global $SysPrefs; if ($SysPrefs->allow_negative_stock() || ($line_item->qty_dispatched <= $qoh)) { return true; } return array($qoh, 'stockmankobg'); } } /* Installs hooks provided by extension modules */ function install_hooks() { global $path_to_root, $Hooks, $installed_extensions; $Hooks = array(); // include current language related $Hooks object if locale file exists $lang_code = clean_file_name($_SESSION['language']->code); if (file_exists($path_to_root . "/lang/" . $lang_code . "/locale.inc")) { include_once($path_to_root . "/lang/" . $lang_code . "/locale.inc"); $code = $_SESSION['language']->code; $hook_class = 'hooks_'.$code; $Hooks[$code] = new $hook_class; unset($code, $hook_class); } // install hooks provided by active extensions if (isset($installed_extensions) && !empty($installed_extensions)) { foreach($installed_extensions as $ext) { $hook_class = 'hooks_'.$ext['package']; if ($ext['active'] && class_exists($hook_class)) { $Hooks[$ext['package']] = new $hook_class; } } } } /* Non active hooks are not included in $Hooks array, so we can use special function to activate. */ function activate_hooks($ext, $comp, $on=true) { global $Hooks; $hooks = @$Hooks[$ext]; if (!$hooks) { $hookclass = 'hooks_'.$ext; if (class_exists($hookclass)) $hooks = new $hookclass; else return true; // extension does not have hooks file } if (!$hooks) return false; elseif ($on) return $hooks->activate_extension($comp, false); else return $hooks->deactivate_extension($comp, false); } /* Calls hook $method defined in extension $ext (if any) */ function hook_invoke($ext, $method, &$data, $opts=null) { global $Hooks; $ret = null; if (isset($Hooks[$ext]) && method_exists($Hooks[$ext], $method)) { set_ext_domain('modules/'.$ext); $ret = $Hooks[$ext]->$method($data, $opts); set_ext_domain(); } return $ret; } /* Calls hook $methods defined in all extensions (if any) */ function hook_invoke_all($method, &$data, $opts=null) { global $Hooks; $return = array(); if (isset($Hooks)) { foreach($Hooks as $ext => $hook) if (method_exists($hook, $method)) { set_ext_domain('modules/'.$ext); $result = $hook->$method($data, $opts); if (isset($result) && is_array($result)) { $return = array_merge_recursive($return, $result); } else if (isset($result)) { $return[] = $result; } set_ext_domain(); } } return $return; } /* Returns first non-null result returned from hook. */ function hook_invoke_first($method, &$data, $opts=null) { global $Hooks; $result = null; foreach($Hooks as $ext => $hook) { if (method_exists($hook, $method)) { set_ext_domain('modules/'.$ext); $result = $hook->$method($data, $opts); set_ext_domain(); if (isset($result)) break; } } return $result; } /* Returns last non-null result returned from modules method. Helps implement hooks overriding by extensions installed later. */ function hook_invoke_last($method, &$data, $opts=null) { global $Hooks; $result = null; $Reverse = array_reverse($Hooks); foreach($Reverse as $ext => $hook) { if (method_exists($hook, $method)) { set_ext_domain('modules/'.$ext); $result = $hook->$method($data, $opts); set_ext_domain(); if (isset($result)) break; } } return $result; } //------------------------------------------------------------------------------------------ // Database transaction hooks. // $type - type of transaction (simplifies cart processing) // $cart - transaction cart // $args is optional array of parameters // // For FA 2.3 prewrite, postwrite and prevoid hooks are implemented for following transaction types: // // ST_BANKPAYMENT, ST_BANKDEPOSIT, ST_BANKTRANSFER, // ST_SALESORDER, ST_SALESQUOTE, ST_SALESINVOICE, ST_CUSTCREDIT, ST_CUSTPAYMENT, ST_CUSTDELIVERY, // ST_LOCTRANSFER, ST_INVADJUST, // ST_PURCHORDER, ST_SUPPINVOICE, ST_SUPPCREDIT, ST_SUPPAYMENT, ST_SUPPRECEIVE, // ST_WORKORDER, ST_MANUISSUE, ST_MANURECEIVE, /* Invoked after transaction has been read from database to cart. Not implemented yet. */ //function hook_db_postread(&$cart, $type) //{ // hook_invoke_all('db_postread', $cart, $type); //} /* Invoked before transaction is written to database. */ function hook_db_prewrite(&$cart, $type) { return hook_invoke_all('db_prewrite', $cart, $type); } /* Invoked after transaction has been written to database. */ function hook_db_postwrite(&$cart, $type) { return hook_invoke_all('db_postwrite', $cart, $type); } /* Invoked before transaction is voided */ function hook_db_prevoid($type, $type_no) { return hook_invoke_all('db_prevoid', $type, $type_no); } //------------------------------------------------------------------------------------------- // // Various hooks // // Alternative exchange rates feeds. // function hook_retrieve_exrate($currency, $date) { return hook_invoke_last('retrieve_exrate', $currency, $date); } // // Generic function called at the end of Tax Report (report 709) // function hook_tax_report_done() { return hook_invoke_all('tax_report_done', $dummy); } // // Amount in words displayed on various documents (especially sales invoice) // function hook_price_in_words($amount, $document) { return hook_invoke_last('price_in_words', $amount, $document); } // // Session handling hook. This is special case of hook class which have to be run before session is started. // If fa_session_manager class is defined in any installed extension, this class provides session handling // for application, otherwise standard php session handling is used. // function hook_session_start($company) { if (class_exists('fa_session_manager')) { global $SessionManager; $SessionManager = new fa_session_manager($company); return $SessionManager->installed; } return false; } // // Third party authentication modules. // Returns true after successfull authentication, false otherwise, null if no login hook is defined. // function hook_authenticate($login, $password) { return hook_invoke_last('authenticate', $login, $password); } /* * Returns the quantity allowed to be dispatched for a particular item * and a "reason" (css classes). * This quantity would be the default value on the delivery note. * The usual use case for this is when a item is in stock, * but has been reserved by someone else. * This allows extensions to implements its own priority algorithm. * This function is by detail_id and not item in case the item is present * more than one in the cart. * If 'skip' is returned, the line will be skipped and not displayed */ function hook_get_dispatchable_quantity($line_item, $location, $date, $qoh) { $result = hook_invoke_first('get_dispatchable_quantity', $line_item, array($location, $date, $qoh)); return $result !== null ? $result : hooks::default_get_dispatchable_quantity($line_item, $location, $date, $qoh); }