Counter for re-opened cases - Salesforce - triggers

I'm traying to create a trigger that count each time a case is re-opened.
What I need is that changing the Status "Cerrado" to "Asignado" add +1
I've this trigger but it doesn't working at all.
Reperturas__c a type number and in the formula I've a 0.
"Cerrado" close the case.
Any solution guys?. Thanks!
trigger caseReOpen on Case (before update) {
for(Case c:trigger.new){
if(trigger.Oldmap.get(c.Id).Status=='Cerrado'){
c.Reaperturas__c ++;
}
}
}

Should work, weird. How's this?
trigger caseReOpen on Case (before update) {
for(Case c: trigger.new){
Case old = trigger.oldMap.get(c.Id);
if(c.Status == 'Asignado' && old.Status == 'Cerrado'){
++c.Reaperturas__c;
}
}
}
Compiled and saved ok? Can you put field history tracking on it, maybe you have something else that resets the counter? Are the actual picklist values like that or are these just labels? You need to use API values in Apex so if they're in English and you just have labels translated - your code won't work.
What if you base the check on !c.IsClosed && old.IsClosed ? It's a computed checkbox, can't be edited directly but it's bit more portable... If in future you add more statuses counting as closing (closed completed, closed cancelled etc?). https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_case.htm

Related

Implementing an increment(+1) filed security using security rules

I want to be able to protect my increment logic from being abused from the front end
my current frond end code
// Initial Payload
const surfacePayload: SurfacePayload = {
gender: selected.gender,
unit: unit.current,
// will increment the count in db by +1
count: increment(+1),
src: currentUser?.uid!,
};
await setDoc(doc(db, docRef, surfacePayload);
my security rules logic is like the following :
// requestData.count types
request.resource.data.count is number && // if the incoming count is a number
request.resource.data.count <= 12 && // this field cannot exceed 12
my big concern however is the this counter is set as a protector for creating docs in a related sub-collection, and it is really ease to keep sending 0 or 1 there is no real check whether the incoming data are only (increment +1)added to the current state of the count in doc... is there any other check that I can implement to make it rock solid, I tried to check again the current state using only (resource.data) but since this check is a part of a bigger check and it is chained so it has failed..
For the case where your document might not exists at first place, you can write separate rules for create and update as shown below:
allow create: if request.resource.data.count == 1; // default value 1
allow update: if request.resource.data.count == resource.data.count + 1;

Purpose of minSupported and maxSupported parameters in getVersion API

I find getVersion API to be a bit hard to grasp. After some manual experiments with workflow changes, I found out that it's perfectly fine to have such a piece of code:
val version = Workflow.getVersion("change#1", 1, 1);
val anotherVersion = Workflow.getVersion("change#2", 2, 2);
Does it mean that the integer version is assigned to a changeId and not workflow instance? Does a single workflow instance/execution keep a set of integer-based versions?
What is the purpose of minSupported and maxSupported parameters? Why simply not to use an API like below?
val version = Workflow.getVersion("change#1")
if (version) {
// code after "change#1" changes
} else {
// code before "#change#1" changes
}
You are correct, the version is assigned to a changeId not a workflow instance. This allow versioning each piece of the workflow code independently. It allows fixing bugs while workflow is already running and didn't reach that part of the code.
The main reason is validation. The getVersion call records in the workflow history maxVersion when the code was executed for the first time. So on replay the correct version is used to guarantee correct replay even if the maxVersion has changed. When a branch is removed the minVersion is incremented. Imagine that such code is deployed by mistake when there is a workflow that needs the removed branch. The getVersion is going to detect that minVersion is larger than the one recorded in the history and is going to fail the decision task essentially blocking the workflow execution instead of breaking it. The same happens if the recorded version is higher than the maxVersion argument.
Update: Answer to the comment
In other words, I'm trying to come up with a situation where using
many different changeIds and not exceeding maxVersion=1 is not enough
They are enough if you don't perform removal of branches. But if you do then having validation of the minimal version is very convenient. For example look at the following code:
val version = Workflow.getVersion("change", 0, 2);
if (version == DEFAULT_VERSION) {
// before change
} else if (version == 1) {
// first change
} else {
// second hange
}
Let's remove the default version:
val version = Workflow.getVersion("change", 1, 2);
if (version == 1) {
// first change
} else {
// second hange
}
Now look at the version without min and max:
var version1 = Workflow.getVersion("change1");
var version2 = Workflow.getVersion("change2");
if (version1 == DEFAULT_VERSION) {
// before change
} else if (version2 == DEFAULT_VERSION) {
// first change
} else {
// second hange
}
Let's remove the default branch:
var version2 = Workflow.getVersion("change2");
if (version2 == DEFAULT_VERSION) {
// first change
} else {
// second hange
}
Note that a workflow that used the last sample code is going to break in unpredictable way if it is routed by mistake to a worker that doesn't know about version2, but only about the original default version. The first example with min max version is going to detect the issue gracefully.

I am thinking of easy account security Developers

If there is "FreezeToken" in the wallet, freeze the wallet.
And if there is "ThawToken" in the wallet, it cancels the freeze.
This code is an example of failure.
let FreezeToken = base58'GwmXnsF3Z5tANgHwmDW7Lf4SwyYNEp4S3QZM3aBFLHwS'
let ThawToken = base58'GK7ZV8xFbh1Qz14Cnr6mLkV93svaZGrurVuaBZocwLZZ'
match tx {
case m : ExchangeTransaction. =>
if (assetBalance(e.sender,ThawToken) >= 1 ) then{true}
else if (assetBalance(e.sender,ThawToken) >= 1 ) then{false}
else true
case _ => false
}
TransferTransaction succeeded but ExchangeTransaction failed.
How do I change this code? please tell me.
I am guessing you are creating a smart account?
From what I see in the code, is that you used 2 times ThawToken, one time this results to true and another time to false. My guess is that you want one from the 2 be replaced by FreezeToken
Also in your example you have "ExchangeTransaction.", this dot doesn't seem needed here from what I can understand from your code.
Also according to the examples it seems that your whole second if structure should be included into {}. Example: https://github.com/wavesplatform/ride-examples/blob/bc8db2342f53fe1554a10dc5aaa211b1542a5ca1/smart-assets/HotPotatoToken.ride#L41
However I think this issue could be solved with a && statement, and as following the second if-then-else is not needed anymore.
What I propose is a check that does following:
Check if ThawToken not in wallet and if that is the case, check if freezetoken is in wallet.
If ThawToken is and FreezeToken is also => wallet free since ThawToken frees it.
If ThawToken is not and FreezeToken is 1 or more => wallet locked since only FreezeToken.
If ThawToken is not and FreezeToken is not => wallet free since no FreezeToken
if (assetBalance(e.sender,ThawToken) == 0 &&
assetBalance(e.sender,FreezeToken) >= 1 ) then{
false
}else{
true
}
Also to block all transactions and indeed freeze the wallet, you would need to filter on another type, for all types use: Transaction, be careful this also disables the option to change the script in case you locked your account.
To block transfer transaction use: TransferTransaction.
All types can be found here:
https://docs.wavesplatform.com/en/smart-contracts/ride-language/standard-library.html

Reload a field from the controller.php

I have a logic hook that changes a field's value, but in order to see the change I need to refresh the whole page... I want it to refresh the field in real time.
So I'm trying to accomplish something like this(https://suitecrm.com/suitecrm/forum/suitecrm-7-0-discussion/21178-refresh-sub-panel-values-when-another-sub-panel-is-updated#75194)
But instead of reloading a whole subpanel through the controller.php I'm trying to find a way to refresh a single field.
Can anyone advise what method needs to be used to reload a field?
For example to reload a subpanel it's
**
showSubPanel('SUBPANEL_NAME',null,true);
**
But what is the JS method that reload a single field?
To refresh a detailView through a logic hook, you can use an easy "hack".
In your logic_hook, place the following js code as your last "echo" before your return or exit:
echo "<script>location.reload();</script>";
Simple but effective.
I couldn't find any built-in functions in suiteCRM that do it, spent a lot of time going through the chrome debugger, but nothing worked.
Here's a video that explains what's happening and the actual code example
https://youtu.be/ebuwWZoSYCk
You need to get the new status from the back-end then update the field inside the controller.php with:
document.querySelector('div[type="enum"][field="$field_to_update"]').innerHTML = "$inventory_status_c";
The whole controller.php file example is here, it all makes sense if you watch the 5 minute video:
class un_inventoryController extends SugarController {
/**
*
*/
function action_SubPanelViewer() {
require_once 'include/SubPanel/SubPanelViewer.php';
// only if this is creation of new sale under accounts, refresh the screen so the salerow subpanel will be refreshed too
if ( array_key_exists('module', $_REQUEST) && array_key_exists('subpanel', $_REQUEST) && array_key_exists('action', $_REQUEST) &&
$_REQUEST['module'] == 'un_inventory' && $_REQUEST['subpanel'] == "un_inventory_leads_1" && $_REQUEST['action'] == "SubPanelViewer") {
write_to_log(array("request" => $_REQUEST), "all conditions filled, custom controller called", true);
// Get the ID of the inventory unit so we can fetch the new status_c field and update the field right away (otherwise we'll have to refresh the page
$inventory = BeanFactory::getBean($_REQUEST["module"], $_REQUEST["record"]);
$inventory_status_c = ucwords(str_replace("_", " ", $inventory->status_c));
$field_to_update = "status_c";
$js=<<<EOQ
<script>
// Update the status
$( document ).ready(function() {
document.querySelector('div[type="enum"][field="$field_to_update"]').innerHTML = "$inventory_status_c";
});
</script>
EOQ;
echo $js;
}
}
}
?>

ag-Grid set filter and sort model without triggering event

I am updating sort & filter models via api:
this.gridApi.setFilterModel(filterModels);
this.gridApi.setSortModel(sortModels);
The problem with this is I have a server request bound to the change even of both sort & filter so when user changes then the data is updated. This means when I change model on code like restoring a state or resetting the filters it causes multiple requests.
Is there a way to update the filter/sort model without triggering the event?
I see there is a ColumnEventType parameter but couldn't see how it works. Can I specify some variable that I can look for inside my event handlers to get them to ignore calls that are not generated from user?
I am trying to manage URL state so when url query params change my code sets the models in the grids but this ends up causing the page to reload multiple times because the onFilter and onSort events get called when the model is set and there is no way I can conceive to prevent this.
At the time, you are going to have to manage this yourself, ie, just before you call the setModel, somehow flag this in a shared part of your app (maybe a global variable)
Then when you react to these events, check the estate of this, to guess where it came from.
Note that at the moment, we have added source to the column events, but they are not yet for the model events, we are planning to add them though, but we have no ETA
Hope this helps
I had to solve similar issue. I found solution which working for my kind of situation. Maybe this help someone.
for (let j = 0; j < orders.length; j++) {
const sortModelEntry = orders[j];
if (typeof sortModelEntry.property === 'string') {
const column: Column = this.gridColumnApi.getColumn(sortModelEntry.property);
if (column && ! column.getColDef().suppressSorting) {
column.setSort(sortModelEntry.direction.toLowerCase());
column.setSortedAt(j);
}
}
this.gridApi.refreshHeader();
Where orders is array of key-value object where key is name of column and value is sorting directive (asc/desc).
Set filter without refresh was complicated
for (let j = 0; j < filters.length; j++) {
const filterModelEntry = filters[j];
if (typeof filterModelEntry.property === 'string') {
const column: Column = this.gridColumnApi.getColumn(filterModelEntry.property);
if (column && ! column.getColDef().suppressFilter) {
const filter: any = this.gridApi.getFilterApi(filterModelEntry.property);
filter['filter'] = filterModelEntry.command;
filter['defaultFilter'] = filterModelEntry.command;
filter['eTypeSelector'].value = filterModelEntry.command;
filter['filterValue'] = filterModelEntry.value;
filter['filterText'] = filterModelEntry.value;
filter['eFilterTextField'].value = filterModelEntry.value;
column.setFilterActive(true);
}
}
}
Attributes in filter:
property - name of column
command - filter action (contains, equals, ...)
value - value used in filter
For anyone else looking for a solution to this issue in Nov 2020, tapping into onFilterModified() might help. This gets called before onFilterChanged() so setting a value here (eg. hasUserManuallyChangedTheFilters = false, etc.) and checking the same in the filter changed event is a possible workaround. Although, I haven't found anything similar for onSortChanged() event, one that gets called before the sorting is applied to the grid.
I am not sure any clean way to achieve this but I noticed that FilterChangedEvent has "afterFloatingFilter = false" only if filterModel was updated from ui.
my workaround is as below
onFilterChanged = event:FilterChangedEvent) => {
if(event.afterFloatingFilter === undefined) return;
console.log("SaveFilterModel")
}