I'm creating a new file in the 'module/Calendar4You/' folder. I saw that other files in that folder included PHP files from the system in respect to the system root, so I tried including Module.php like:
PHP Code:
include_once('vtlib/Vtiger/Module.php');
Which gave me an error I understood, because I had to use:
PHP Code:
include_once('../../vtlib/Vtiger/Module.php');
to tell PHP to move back two levels first. But now I receive an error when Module.php tries to include files ("ModuleBasic.php") in its turn, because it is also trying to use a relative path. How come other PHP files can include using the system root, and I can only include using a relative one? Must be an easy answer but I can't see it.
I'm in the process of creating an XLM output for accounting software. At first I wanted to base this on the 'Inventory details' module, but there's a problem. Here's what I have so far:
include_once('vtlib/Vtiger/Module.php'); global $adb;
// Create DOM document $domtree = new DOMDocument('1.0', 'UTF-8');
// Create root element $xmlRoot = $domtree->createElement('xml');
// Append XML element to root $xmlRoot = $domtree->appendChild($xmlRoot);
// Get all invoices $invoiceresult = $adb->pquery('SELECT invoiceid, subject, invoicedate, invoice_no FROM vtiger_invoice',array());
// Loop invoices while ($invoicerow=$adb->fetch_array($invoiceresult)) {
// Set empty 'previousInvoice' $previousInvoice = '';
// Get inventory detail records for this invoice $inventoryresult = $adb->pquery('SELECT productid, account_id, related_to FROM vtiger_inventorydetails WHERE related_to=?',array($invoicerow[invoiceid]));
// Loop inventory details while ($inventoryrow=$adb->fetch_array($inventoryresult)) {
// Set and append XML children to xml root element only when not the same number as the last iteration if ($inventoryrow[related_to] != $previousInvoice) { // Create the element in the DOM $currentInvoice = $domtree->createElement('invoice'); // Append it to the XML tree $currentInvoice = $xmlRoot->appendChild($currentInvoice); // Create the invoice number element in the DOM $currentInvoiceNo = $domtree->createElement('invoicenumber', $invoicerow[invoice_no]); // Append it to the current invoice $currentInvoiceNo = $currentInvoice->appendChild($currentInvoiceNo); // Set the invoice date to correct date format $date = new DateTime($invoicerow[invoicedate]); // Create the invoice date element in the DOM $currentInvoiceDate = $domtree->createElement('invoicedate', $date->format('d-m-Y')); // Append it to the current invoice $currentInvoiceDate = $currentInvoice->appendChild($currentInvoiceDate); // Create an element called 'products' $currentInvoiceProducts = $domtree->createElement('products'); // Append it to the invoice $currentInvoiceProducts = $currentInvoice->appendChild($currentInvoiceProducts);
// Add an 'account' element to the DOM $currentAccount = $domtree->createElement('accounts'); // append the account element to the current invoice $currentAccount = $currentInvoice->appendChild($currentAccount); // Select account details from the database based on account_id in inventory details line $accountresult = $adb->pquery('SELECT accountname, account_no FROM vtiger_account WHERE accountid=?',array($inventoryrow[account_id])); // Get the account's row from the query $accountName = $adb->query_result_rowdata($accountresult,0); // Create a DOM element for the current account name $currentAccountName = $domtree->createElement('accountname',$accountName[accountname]); // Append this to the currentAccount $currentAccountName = $currentAccount->appendChild($currentAccountName); // Create a DOM element for the current account no $currentAccountNo = $domtree->createElement('accountno',$accountName[account_no]); // Append this to the currentAccount $currentAccountNo = $currentAccount->appendChild($currentAccountNo); }
// Select products from the database based on product id from inventory details $productresult = $adb->pquery('SELECT productname FROM vtiger_products WHERE productid=?',array($inventoryrow[productid])); while ($product=$adb->fetch_array($productresult)) { // Create an XML dom element for each product $currentProduct = $domtree->createElement('product',$product[productname]); // Append each one to the 'CurrentProducts' element $currentProduct = $currentInvoiceProducts->appendChild($currentProduct); }
$previousInvoice = $inventoryrow[related_to];
}
}
$domtree->save('TESTXML.xml'); ?>
Which produces:
Code:
<xml><invoice><invoicenumber>20151252</invoicenumber><invoicedate>09-11-2015</invoicedate><products><product>Zak granulaat</product><product>Verpakking- en verzendkosten</product><product>Zak granulaat</product><product>Verpakking- en verzendkosten</product></products><accounts><accountname>Schurer Kamphuis</accountname><accountno>ACC962</accountno></accounts></invoice><invoice><invoicenumber>20151256</invoicenumber><invoicedate>06-11-2015</invoicedate><products><product>GVL40</product><product>Verpakking- en verzendkosten</product></products><accounts><accountname>Autobedrijf Taris</accountname><accountno>ACC1055</accountno></accounts></invoice><invoice><invoicenumber>20151261</invoicenumber><invoicedate>06-11-2015</invoicedate><products/><accounts><accountname>Autoherstel Charlois</accountname><accountno>ACC1979</accountno></accounts></invoice></xml>
That's all very nice, but as you can see the first invoice holds the same products twice. This is because I edited and saved this invoice twice. I checked the database and the Inventory details module creates a record each and every time the related module record saves. This could be fine, maybe it's the designers intended behaviour, so not a complaint about the module, but not the behaviour I want.
So I searched for a way to list products and services related to an invoice from the traditional inventory module. I found that in the inventory_products_rel table all products ever listed get a record, and products that belong to the same inventory (list) receive the same inventory number. What I can't find out is how an invoice, SO or something like this knows which inventory number to use. I need this information to list the products, prices etc. in my XML.
Okay, so I've spent a couple of hours reading the entire PearDatabase file, and have two conclusions:
- Having learned a lot about PHP the last year, I still need more knowledge.
- The $adb is the system-wide used instance of the PearDatabase class, so all object methods live there through which you can communicate with the database.
Digging further into the method use of $adb, I found this example:
Code:
// Extra function to create unique invoice_number
function getInvoiceNumber() {
global $adb;
$sql="select max(subject) as aantal from vtiger_invoice where
Year(invoicedate) = year(now())";
$result = $adb->query($sql);
$invoice_subject= $adb->query_result($result,0,"aantal");
So basically the two most basic methods are 'query' in which you perform a query, and 'query_results', that'll give you an array with results. If anyone knows more good reading sources about this, please reply with links so I can learn more about his object, since it clearly seems to be one of the most important ones of the system.
I was trying if the new corebos could process negative amounts, so I took an existing quote and filled in -1 in stead of 1. This worked (great improvement in comparison to vTiger). But when I wanted to change the amount back to 1 I got the following fatal error (debug turned on):
Code:
Fatal error: Uncaught exception 'WebServiceException' with message 'Database fout tijdens uitvoeren van de gevraagde operatie' in /home/guidog/domains/cbx-nederland.nl/public_html/crmdevelop/include/Webservices/VtigerModuleOperation.php:66 Stack trace: #0 /home/guidog/domains/cbx-nederland.nl/public_html/crmdevelop/include/Webservices/Retrieve.php(44): VtigerModuleOperation->retrieve('36x35933') #1 /home/guidog/domains/cbx-nederland.nl/public_html/crmdevelop/modules/com_vtiger_workflow/VTEntityCache.inc(17): vtws_retrieve('36x35933', Object(Users)) #2 /home/guidog/domains/cbx-nederland.nl/public_html/crmdevelop/modules/com_vtiger_workflow/VTEntityCache.inc(97): VTWorkflowEntity->__construct(Object(Users), '36x35933') #3 /home/guidog/domains/cbx-nederland.nl/public_html/crmdevelop/modules/com_vtiger_workflow/VTEventHandler.inc(45): VTEntityCache->forId('36x35933') #4 /home/guidog/domains/cbx-nederland.nl/public_html/crmdevelop/include/events/VTEventTrigger.inc(142): VTWorkflowEventHandler->handleEvent('vtiger.entity.a...', in /home/guidog/domains/cbx-nederland.nl/public_html/crmdevelop/include/Webservices/VtigerModuleOperation.php on line 66
It seems there was some database error while trying to save. I don't know if this is related to the negative amount. I see some 'workflow' mentions in the error message, but as far as I know there are no workflows to update inventory on saving of quotes.
I will proceed to try other existing quotes to see if this is a one-time thing or structural. UPDATE
I tested some other quotes the same way, no problems there. Maybe this was a one-time thing, some error for this particular quote. Still I'd like to understand the error, so if anyone has some idea...
OK, for my own educational purposes on CoreBOS and to fullfill an actual need of ours, I'd like to set up this case here and see if I studied correctly:
We'd like to be able to create a Sales Order directly from a ticket. For this I need to create a "detail View Widget" following the post here. I have to register the widget following the system's API, and fill out the URL so that in the GET superglobal the Sales Order create view starts with the GET variables I want.
I updated my CoreBOS install to the latest files, github dated 4-11-2015. I've got it all working pretty nicely, but have one problem. I used to make PDF templates that output either a product or a service, based on what was listed. I used variables for both in the same table cell, since an empty value would just not be shown.
For instance, I could use
Code:
$PRODUCT_NAME$ $SERVICE_NAME$
which would output an empty string for productname when the line is a service and an empty string for servicename when the line was a product. I did NOT update PDF maker, but the behaviour has changed, I can no longer do this because for instance when I have a line that is product, the PDF will also output $SERVICE_NAME$.
In other words, the system doesn't recognise these values as variables anymore when they're empty.
The guys at corebos did some improvements on the Calendar4You module, which are great. Just one specific thing bothered me. We use the calendar so that the planner can oversee three, four different people at once. The new calendar view changed the event layout from inline to tabled. This is fine, but when you try to watch a lot of appointments in one day the appointments get narrower and text falls completely out. To change the behaviour back to default, open
is it possible to link all documents : Quotes, Sales Order, Invoice , Purchase order , IssueCards , ReceiptCards to cbEmployee as it is now with Accounts/Contacts?
All my COREBOS updater updates are OK, except for this one. I get the error:
INSERT INTO vtiger_cron_task (name ,handler_file ,frequency ,laststart ,lastend ,status ,module ,sequence ,description) VALUES ('Native Backup', 'cron/modules/VtigerBackup/VtigerBackup.service', '86400', '0', '0', '0', 'VtigerBackup', '7', 'Backup with no external tools. Can easily run into memory limitations and really slow down the server. Good for smaller sets of information.')
Changeset cbcronbackup applied!
ERROR: Class called without update record in application!!