Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Migrating 'old style' custom validation to a Business Map validation
#1
I want to migrate a validation I have in a custom validation file to a Business Map Validation. The validation I have now looks like this:

SalesOrderValidation.php
PHP Code:
<?php

global $log,$currentModule,$adb,$current_user;

$screen_values json_decode($_REQUEST['structure'],true);

$q "SELECT vtiger_groups.groupname FROM vtiger_groups INNER JOIN vtiger_users2group ON vtiger_groups.groupid = vtiger_users2group.groupid WHERE vtiger_users2group.userid = ?";
$p = array($current_user->id);
$r $adb->pquery($q$p);

$groups = array();

while (
$groupname $adb->fetch_array($r)) {
 
$groups[] = $groupname['groupname'];
}

$q "SELECT sostatus FROM vtiger_salesorder WHERE salesorderid = ?";
$p = array(vtlib_purify($screen_values['record']));
$r $adb->pquery($q$p);
$current_status $adb->query_result($r0'sostatus');

$q "SELECT vtiger_role.rolename FROM vtiger_role INNER JOIN vtiger_user2role ON vtiger_role.roleid = vtiger_user2role.roleid WHERE vtiger_user2role.userid = ?";
$p = array($current_user->id);
$r $adb->pquery($q$p);
$rolename $adb->query_result($r0'rolename');

if (!
in_array('Debiteurenadministratie'$groups) && $current_status == 'Wacht op betaling' && $screen_values['sostatus'] != 'Wacht op betaling') {
 echo 
'U mag de status niet van \'Wacht op betaling\' af halen'// Translation: You are not allowed to change the status from 'Wacht op betaling' to anything else
 
die();
} else if (
$rolename != 'Directeur' && $screen_values['sostatus'] == 'Cancelled' && $current_status != 'Cancelled') {
 echo 
'U mag deze order niet annuleren, alleen de Directeur mag dat'// Translation: You are not allowed to cancel an order, only the CEO is.
 
die();
}

echo 
'%%%OK%%%'

This basically checks the user's role and group to see what they can and cannot do to specific SalesOrder statuses. Now I want to migrate this to a Busines map validation. I was thinking along these lines:

Business Map
Code:
<map>
 <originmodule>
   <originname>SalesOrder</originname>
 </originmodule>
 <fields>
   <field>
     <fieldname>sostatus</fieldname>
     <validations>
       <validation>
         <rule>custom</rule>
         <restrictions>
         <restriction>modules/SalesOrder/ValidateStatus.php</restriction>
         <restriction>check_sostatus_permissions</restriction>
         <restriction>validate_sostatus_permissions</restriction>
         </restrictions>
       </validation>
     </validations>
   </field>
 </fields>
</map>

modules/SalesOrder/ValidateStatus.php

PHP Code:
<?php

function validate_sostatus_permissions() {

global 
$log,$currentModule,$adb,$current_user;

$screen_values json_decode($_REQUEST['structure'],true);

$q "SELECT vtiger_groups.groupname FROM vtiger_groups INNER JOIN vtiger_users2group ON vtiger_groups.groupid = vtiger_users2group.groupid WHERE vtiger_users2group.userid = ?";
$p = array($current_user->id);
$r $adb->pquery($q$p);

$groups = array();

while (
$groupname $adb->fetch_array($r)) {
 
$groups[] = $groupname['groupname'];
}

$q "SELECT sostatus FROM vtiger_salesorder WHERE salesorderid = ?";
$p = array(vtlib_purify($screen_values['record']));
$r $adb->pquery($q$p);
$current_status $adb->query_result($r0'sostatus');

$q "SELECT vtiger_role.rolename FROM vtiger_role INNER JOIN vtiger_user2role ON vtiger_role.roleid = vtiger_user2role.roleid WHERE vtiger_user2role.userid = ?";
$p = array($current_user->id);
$r $adb->pquery($q$p);
$rolename $adb->query_result($r0'rolename');

if (!
in_array('Debiteurenadministratie'$groups) && $current_status == 'Wacht op betaling' && $screen_values['sostatus'] != 'Wacht op betaling') {
 return 
'U mag de status niet van \'Wacht op betaling\' af halen'// Translation: You are not allowed to change the status from 'Wacht op betaling' to anything else
 
die();
} else if (
$rolename != 'Directeur' && $screen_values['sostatus'] == 'Cancelled' && $current_status != 'Cancelled') {
 return 
'U mag deze order niet annuleren, alleen de Directeur mag dat'// Translation: You are not allowed to cancel an order, only the CEO is.
 
die();
}

return 
true;


My questions
  • Do I have the same 'screen_values' array at my disposal?
  • Am I correct to transform my "echo's" into "returns" and expect it to work?
  • Am I doing something else terribly wrong?
Reply
#2
You will be able to access the $_REQUEST and get screen_values as usual.

No, these functions must return TRUE or FALSE. The output message is the fourth <restriction>, the fourth, if given, is a label that will be translated in the context of the module

A quick read and a few comments:

- control the case of inline edit where you do not have all the field values in screen_values
- you don't need the die() after the return
Joe
TSolucio
Reply
#3
Ah, so it would be better to create multiple validations for each use case I think? I now use one script that checks multiple possible errors, but it would be better to split them I think?

Quote:control the case of inline edit where you do not have all the field values in screen_values
Do you mean the 'old' field value versus the value the user is trying to change to, or do you mean not all the record values?

Quote:you don't need the die() after the return
Thanks for the heads up, that was a remnant from when the script used 'echo' in stead of 'return'.
Reply
#4
I mean, not all the record values as in detail view you only get the field that is being changed

Yes, I think the idea is to have individual validations
Joe
TSolucio
Reply
#5
That field get automatically passed into the function you point to in the business map right? You just have to setup the function to accept the argument.
Reply
#6
Yes, the validation function receives the information it needs, I think it is the field, the value and some other information.
Joe
TSolucio
Reply
#7
Do you have a working example of this?

Been playing with this, you get the fieldname (param1) and the field value you were trying to set (param2). I do think the validation engine would allow for more params though. If we do inline edit now, we can't really get anything from the database since all we have is the fieldname and value. If we wanted to check other fields on that record, we don't know which ID we should retrieve.


UPDATE:
Wait: you DO get the full record. There is a fourth parameter, even though the third one is empty. That one will have all the information you need. Will update this post with a tutorial
Reply
#8
Here's how you do it:

Let's say you only want people from a specific group to be able to change the status of a SalesOrder when it is set to a specific status. For instance, if that status is 'Waiting for payment', you only want certain people to be able to 'release' that order.

FIRST
You create a businessmap of the 'Validation' type, for SalesOrders:
Code:
<map>
 <originmodule>
   <originname>SalesOrder</originname>
 </originmodule>
 <fields>
   <field>
     <fieldname>sostatus</fieldname>
     <validations>
       <validation>
         <rule>custom</rule>
         <restrictions>
         <restriction>modules/SalesOrder/mySalesOrderValidation.php</restriction>
         <restriction>CanThisUserDoThis</restriction>
         <restriction>checkPaymentStatusGroup</restriction>
         <restriction>LBL_NOT_ALLOWED_STATUS_ONLY_GROUP</restriction>
         </restrictions>
       </validation>
     </validations>
   </field>
 </fields>
</map>
You specify you want to keep an eye on the sostatus field and that you want to use a custom rule. You need 4 restriction parameters:
  • Where the file is that your validation function is in
  • A name for your validation, doesn't really matter
  • The name of the function you defined in that file
  • The array key in the language file in SalesOrders (can also be a custom lang file) where your message lives (that will be shown when the validation fails)
SECOND
You create the file, with the function:
PHP Code:
function checkPaymentStatusGroup($fieldname$fieldvalue$params$entity) {
 global 
$adb$current_user$log;
 
$current_status $entity['current_sostatus'];

 
$q "SELECT vtiger_groups.groupname FROM vtiger_groups INNER JOIN vtiger_users2group ON vtiger_groups.groupid = vtiger_users2group.groupid WHERE vtiger_users2group.userid = ?";
 
$p = array($current_user->id);
 
$r $adb->pquery($q$p);

 
$groups = array();
 while (
$groupname $adb->fetch_array($r)) {
 
$groups[] = $groupname['groupname'];
 }

 if (!
in_array('Payment Checking Group'$groups) && $current_status == 'Waiting for payment' && $entity['sostatus'] != 'Waiting for payment') {
 return 
false;
 } else {
 return 
true;
 }

This function will receive four parameters:
  • The fieldname of the field that was edited. Not very usefull, you created the Map for that field so you already know the name
  • The fieldvalue that a user is TRYING to save
  • an empty array
  • The record you are saving (array). This has some interesting features:
    • A 'record' key, that holds the crm ID of the record you are editing.
    • A 'from_link' key, that holds the view (e.g. DetailView)
    • Also things like the 'convertmode', 'action', 'return_action' and such
    • Best of all, ALL the current fields of the record, prefixed with 'current_'. So for instance, the current SalesOrder status would be in 'current_sostatus'.
So now we can check to which groups the current user belongs to, what the current salesorder status is and what he/she is trying to change it to. If we are fine with that, we return 'true', if we are not, we return 'false'.

Returning false will show the user an alert with the message from the language file that has the key you set in the business map (last restriction).
Reply
#9
Nice!! Thanks for the explanation and sharing :-)
Joe
TSolucio
Reply
#10
I do have one last problem though. I want to create a business map that checks the same field twice. Don't seem able to do that. They both work when I add just one of them, but when applied both, they don't. The reason is that I want to show a different message based on what went wrong. Right now, the second one overwrites the first one for that field.

Wait, let me try to put TWO validations in one field.. how stupid of me..

No, does't work either...
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)