CoreBOSBB
Using the standard 'create invoice from salesorder' in workflows - Printable Version

+- CoreBOSBB (https://discussions.corebos.org)
+-- Forum: Development (https://discussions.corebos.org/forumdisplay.php?fid=18)
+--- Forum: coreBOS Development (https://discussions.corebos.org/forumdisplay.php?fid=4)
+--- Thread: Using the standard 'create invoice from salesorder' in workflows (/showthread.php?tid=338)

Pages: 1 2 3


RE: Using the standard 'create invoice from salesorder' in workflows - joebordes - 08-07-2016

Let me know how it goes.


RE: Using the standard 'create invoice from salesorder' in workflows - Guido1982 - 08-08-2016

(08-07-2016, 03:33 PM)joebordes Wrote: The missing ampersand has nothing to do with the problem. The correct way to define the task is WITH the ampersand.

When you extend a class





PHP Code:
class CBTagTask extends VTTask


you inherit all of it's methods, but if that class has defined any method as "abstract" your new class MUST implement those and they must follow the exact same profile as defined in the base class.

You can see here

https://github.com/tsolucio/corebos/blob/master/modules/com_vtiger_workflow/VTTaskManager.inc#L166

that the doTask() method gets the entity by reference so your class, which constructs upon that one has to define that method like that.

Thanks, I've seen abstract class definitions but never quite knew what they were. I know about interfaces (never implemented them but they're in the book I'm reading) but never knew abstract classes had similar behaviour. Anyway, the thing I am curious about is why your example does not have to implement the argument as a reference here.

(08-07-2016, 03:55 PM)joebordes Wrote: Why did you change the name here:

https://github.com/Luke1982/corebos/blob/createInvoiceFromSO_WF/modules/com_vtiger_workflow/tasks/create_invoice_from_so.inc#L71




PHP Code:
$data['LineItems'] = $wsso['pdoInformation']; 

shouldn't it be




PHP Code:
$data['pdoInformation'] = $wsso['pdoInformation']; 

??

I've used this code to start:

PHP Code:
include_once 'include/Webservices/Revise.php';
include_once 
'modules/Users/Users.php';

try {
 
       $user = new Users();
 
       $current_user $user->retrieveCurrentUserInfoFromFile(Users::getActiveAdminId());
 
$wsid vtws_getWebserviceEntityId('Invoice''CRMID'); // CRMID => Is the Existing Record ID in the CRM.
 
$lineItem1=array('productid'=>'6x91','listprice'=>'2000','quantity'=>'1');
 
       $lineItem2=array('productid'=>'6x76','listprice'=>'5000','quantity'=>'32');
 
       $data = array (
 
              'subject' => 'Mangoes Goes Revised',
 
              'sostatus' => 'Created',
 
              'invoicestatus' => 'Created',
 
              'hdnTaxType' => 'group',
 
              'conversion_rate' => 1,
 
              'bill_street'=>'Mango Street',
 
              'productid'=>'6x91',
 
              'id'=> $wsid,
 
              'hdnDiscountAmount'=>'20',
 
              'LineItems'=>array($lineItem1$lineItem2),
 
      );
 
      $invoice vtws_revise($data$current_user);

 echo 
'<pre>';
 
print_r($invoice);


} catch (
WebServiceException $ex) {
 echo 
$ex->getMessage();

from here. There the array label is 'LineItems', so I assumed this was the correct label for invoice creation. Also, this worked when I tested using a separate test file.
[url=https://wiki.vtiger.com/index.php/ServerAPI_reference_manual][/url]

(08-07-2016, 03:48 PM)joebordes Wrote: Next up is the default value for the due date. You should not need to setup the workflow task to get the duedate offset. This is better done using (Field) Mapping Business Mapping


http://corebos.org/documentation/doku.php?id=en:adminmanual:businessmappings:mapping

This type of business mapping serves to define field values to capture when converting from one module to another, but it also serves to set default values when creating a new record. You can achieve this by creating a mapping with the same module name for both sides, for example, in this case Invoice2Invoice. Just to test it I created the mapping below and now when I create a new invoice my due date is set to 30 days from today.



Code:
<map>
  <originmodule>
    <originname>Invoice</originname>
  </originmodule>
  <targetmodule>
    <targetname>Invoice</targetname>
  </targetmodule>
  <fields>
    <field>
      <fieldname>duedate</fieldname>
      <Orgfields>
        <Orgfield>
          <OrgfieldName>add_days(get_date('today'), 30)</OrgfieldName>
          <OrgfieldID>expression</OrgfieldID>
        </Orgfield>
      </Orgfields>
    </field>
  </fields>
</map>



we must get the workflow task to use this mapping because with that you can define ANY field as you like without having to modify the workflow and it will also serve for normal user creation.

give that a try just to get a hang of how incredibly powerful the mappings are and how much you can really customize coreBOS now without touching to much code.

I continue....

Thanks, I'll give that a try. But one question: would it be possible to create one workflow that sets the date of the invoice 30 days from now and create another that sets the date 60 days? So we can check certain conditions and base the invoice duedate on that? I certainly see the power of the business maps, but would it be an idea to create a dropdown in the workflow config where you can select a business map to execute or does my limited knowledge of the module make me think in the wrong direction here?

About the label 'pdoInformation' to 'LineItems': even if this was wrong, the workflow still should've worked. I transfer the complete $wsso array into $data first, thereby creating a label called 'pdoInformation' in the $data array. I create the LineItems label as a copy since I thought this is what the system wanted on invoice creation through webservice. Although this worked in a separate testfile, it does not when you use it in a workflow. I wish there was a better way of debugging workflows, so I could see what's going on..

(08-07-2016, 04:33 PM)joebordes Wrote: Ok, I had a look. This is what you have to do

https://github.com/tsolucio/corebos/blob/master/modules/Invoice/EditView.php#L57

basically repeat that logic. It will be something in this line:



PHP Code:
$focus CRMEntity::getInstance('Invoice');

list(
$so_wsid,$soid) = explode('x',$entity->getId());
$so_focus CRMEntity::getInstance('SalesOrder');
$so_focus->id $soid;
$so_focus->retrieve_entity_info($soid"SalesOrder");
$focus getConvertSoToInvoice($focus$so_focus$soid);  // this will do the Mapping for the duedate and others SalesOrder2Invoice

 // we do this to get the pdoInformation array
$wsso vtws_retrieve($entity->getId(), $current_user);
$focus->column_fields['pdoInformation'] = $wsso['pdoInformation'];

$invoice vtws_create('Invoice'$focus->column_fields$current_user); 

that should be all you need.

Please BE CAREFUL I have NOT tested the code above

I will test this and let you know.


RE: Using the standard 'create invoice from salesorder' in workflows - joebordes - 08-08-2016

> Tag task was uploaded incorrectly and then fixed, note that your reference is of July 2014 and then it was fixed in Oct 2014, it is now correct in the latest version of the code

> your example code is from VT6, we implemented the lines differently


RE: Using the standard 'create invoice from salesorder' in workflows - joebordes - 08-08-2016

Quote:one question: would it be possible to create one workflow that sets the date of the invoice 30 days from now and create another that sets the date 60 days? So we can check certain conditions and base the invoice duedate on that? I certainly see the power of the business maps, but would it be an idea to create a dropdown in the workflow config where you can select a business map to execute or does my limited knowledge of the module make me think in the wrong direction here?


I don't think so, please open another thread with this question and give me an example of the conditions.


RE: Using the standard 'create invoice from salesorder' in workflows - joebordes - 08-08-2016

Quote:About the label 'pdoInformation' to 'LineItems': even if this was wrong, the workflow still should've worked. I transfer the complete $wsso array into $data first, thereby creating a label called 'pdoInformation' in the $data array. I create the LineItems label as a copy since I thought this is what the system wanted on invoice creation through webservice. Although this worked in a separate testfile, it does not when you use it in a workflow. I wish there was a better way of debugging workflows, so I could see what's going on..



you are right, that should have worked.
it is not easy to debug workflow tasks, we have created the separate background.log file, which you can write to using the global variable $logbg
That may help a little as we basically use that log for background tasks like workflows.


RE: Using the standard 'create invoice from salesorder' in workflows - Guido1982 - 08-08-2016

(08-08-2016, 10:53 AM)joebordes Wrote: > Tag task was uploaded incorrectly and then fixed, note that your reference is of July 2014 and then it was fixed in Oct 2014, it is now correct in the latest version of the code

> your example code is from VT6, we implemented the lines differently

Ah, so basically I was looking at a wrong example?

PHP Code:
$focus getConvertSoToInvoice($focus$so_focus$soid);  // this will do the Mapping for the duedate and others SalesOrder2Invoice 

Is this native CRM code? I mean the 'getConvertSoToInvoice' function?


RE: Using the standard 'create invoice from salesorder' in workflows - joebordes - 08-08-2016

Yes
Yes

:-)


RE: Using the standard 'create invoice from salesorder' in workflows - Guido1982 - 08-08-2016

I don't fully understand this code:

PHP Code:
$focus CRMEntity::getInstance('Invoice');

list(
$so_wsid,$soid) = explode('x',$entity->getId());
$so_focus CRMEntity::getInstance('SalesOrder');
$so_focus->id $soid;
$so_focus->retrieve_entity_info($soid"SalesOrder");
$focus getConvertSoToInvoice($focus$so_focus$soid);  // this will do the Mapping for the duedate and others SalesOrder2Invoice

 // we do this to get the pdoInformation array
$wsso vtws_retrieve($entity->getId(), $current_user);
$focus->column_fields['pdoInformation'] = $wsso['pdoInformation'];

$invoice vtws_create('Invoice'$focus->column_fields$current_user); 

First, we create an invoice instance. Then we get the SO's CRM id. We also create a Salesorder instance. Both instances are empty, they still have to be filled with specific data. We do that by calling 'retrieve_entity_info' which we feed the CRM id but still, one line before that we have to manually set the SO's instance with the SO ID? Then, after we've told so_focus which ID it needs to base itself on, we have to feed the soid yet again to the 'getConvertSoToInvoice' function?


I am testing the instance of invoice now, after I call the getConvertSoToInvoice. It seems now I know why the native Account number and salesorder ID were never filled out on creating an invoice ffrom a sales order: this function does not fill them.

I now have the following code in a test file:


PHP Code:
<?php

error_reporting
(E_ERROR);
ini_set("display_errors""on");

include_once 
'include/Webservices/Retrieve.php';
include_once 
'include/Webservices/Create.php';
include_once 
'modules/Users/Users.php';

$user = new Users();
$current_user $user->retrieveCurrentUserInfoFromFile(Users::getActiveAdminId());

/*=========== Retrieve SO =============*/
// Retrieve SO crmid
global $adb;
$query 'SELECT salesorderid FROM vtiger_salesorder WHERE salesorder_no=?';
$params = array('ORD160935');
$result $adb->pquery($query$params);
$so_crmid $adb->query_result($result0'salesorderid');

// Get the SO
$so_focus CRMEntity::getInstance('SalesOrder');
$so_focus->id $so_crmid;
$so_focus->retrieve_entity_info($so_crmid"SalesOrder");

// Create invoice instance
$focus CRMEntity::getInstance('Invoice');
$focus getConvertSoToInvoice($focus$so_focus$so_crmid);

$invoice vtws_create('Invoice'$focus->column_fields$current_user);

echo 
"<pre>";
var_dump($focus->column_fields);
echo 
"</pre>"

The first lines are only for testing of course (the lines that get the SO crm id from the DB). It gives me:

Code:
Fatal error: Uncaught exception 'WebServiceException' with message 'Permission to perform the operation is denied for id' in /

Wait, again the WEBSERVICE ID of course.... stupid of me.


RE: Using the standard 'create invoice from salesorder' in workflows - Guido1982 - 08-08-2016

In short, the code you suggested may work if you get the WEBSERVICE id for each related ID you enter. so for account, assigned user and such: you need to overwrite it to get the webservice ID's. Your approach was to get the native invoice instance and add the product lines through webservice. I think it is best the other way around: get a webservice object and then overwrite with the native invoice object where needed.


RE: Using the standard 'create invoice from salesorder' in workflows - joebordes - 08-08-2016

You can use
PHP Code:
DataTransform::sanitizeReferences() 

to accomplish this.

Have a look here at how I use it to unit test the DataTransform API

https://github.com/tsolucio/coreBOSTests/blob/master/include/Webservices/DataTransformTest.php#L55

basically get the webservice object for invoice and pass it into sanitizeReferences with the data array