How to validate if sum of values are equal in Validation - laravel

I have this accounting project where I need to validate if debit and credit are equal before saving to the database.
e.g
accounts: [
{
id: 1,
account_id: 1,
debit: 1000
},
{
id: 2,
account_id: 5,
credit: 1500
},
{
id: 3,
account_id: 8,
debit: 500
}
]
By the way I am using axios and lodash.
axios.post('/api/journals', {
accounts : map(this.accounts, function(account) {
account_id: account.account_id,
debit: account.debit,
credit: account.credit
})
}
Can anyone suggest how to implement this validation rule.

The validation rule has nothing to do with Laravel or VueJS. All you need is to use lodash to iterate through your accounts array, sum the debit and credit numbers separately, and compare them thereafter:
var debitSum = _.reduce(data.accounts, function(sum, account) {
return (account.debit || 0) + sum;
}, 0);
var creditSum = _.reduce(data.accounts, function(sum, account) {
return (account.credit || 0) + sum;
}, 0);
console.log('Debit: ' + debitSum + '; Credit: ' + creditSum);
if (debitSum !== creditSum) {
// Debit and credit sums do not match
} else {
// Debit and credit sums match
}
The code above uses the _.reduce() method to calculate the sum of debit/credit amounts. Since debit and credit keys are not guanranteed to be present all the time, we use the || operator to assign a value of 0 when it is falsy (e.g. undefined, null, 0, empty string, etc.)
Here's a proof-of-concept example:
var data = { accounts: [{
id: 1,
account_id: 1,
debit: 1000
},
{
id: 2,
account_id: 5,
credit: 1500
},
{
id: 3,
account_id: 8,
debit: 500
}
]};
var debitSum = _.reduce(data.accounts, function(sum, account) {
return (account.debit || 0) + sum;
}, 0);
var creditSum = _.reduce(data.accounts, function(sum, account) {
return (account.credit || 0) + sum;
}, 0);
console.log('Debit: ' + debitSum + '; Credit: ' + creditSum);
if (debitSum !== creditSum) {
console.log('Debit and credit are not equal!');
} else {
console.log('All ok');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

Related

This code calculates the total price of a list of items but how can i improve it?

function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
if (items[i].type === "food") {
total += items[i].price * 1.1;
} else {
total += items[i].price;
}
}
return total;
}
const items = [
{ type: "food", price: 10 },
{ type: "clothing", price: 20 },
{ type: "electronics", price: 30 }
];
console.log(calculateTotal(items));
I need to improve on this code.
I have tried improving the variable description. here is the code again with improved variables
function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.type === "food") {
total += item.price * 1.1;
} else {
total += item.price;
}
}
return total;
}
const items = [
{ type: "food", price: 10 },
{ type: "clothing", price: 20 },
{ type: "electronics", price: 30 }
];
console.log(calculateTotal(items));
what else can i try improving on in this code?
You can add a factor const with shorted if syntax for better readability
function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
const item = items[i];
const factor = (item.type === "food") ? 1.1 : 1
total += item.price * factor;
}
return total;
}
const items = [
{ type: "food", price: 10 },
{ type: "clothing", price: 20 },
{ type: "electronics", price: 30 }
];
console.log(calculateTotal(items));
Or using forEach JavaScript syntax you can use:
function calculateTotal(items) {
let total = 0;
items.forEach((item) => {
total += ((item.type === "food") ? item.price * 1.1 : item.price)
})
return total;
}
Also, you can add factor property inside the item object itself to 'special' items (with factor != 1) like this:
const items = [
{ type: "food", price: 10, factor: 1.1 },
{ type: "clothing", price: 20 },
{ type: "electronics", price: 30 }
];
Than you can use the reduce method like this:
function calculateTotal(items) {
let total = items.reduce((acc, item) => {
return acc + item.price * (item?.factor || 1)
}, 0)
return total;
}
Or just:
function calculateTotal(items) {
return items.reduce((acc, item) => {
return acc + item.price * (item?.factor || 1)
}, 0)
}

How can I filter rows by value and then count and plot pie chart and histogram?

My data look like this:
{
"raw_data": [
{
"agebracket": "",
"currentstatus": "Hospitalized",
"dateannounced": "05/06/2020",
"gender": "",
....
},
{
"agebracket": "",
"currentstatus": "Recovered",
"dateannounced": "05/06/2020",
"gender": "",
.........
},
{
"agebracket": "",
"currentstatus": "Hospitalized",
"dateannounced": "05/06/2020",
"gender": "",
.......
},
I am able to plot dc graph for the whole dataset. But now I want to filter it by "currentstatus" --> "Recovered", "Hospitalized", "Deceased".
Right now it looks like this:
https://blockbuilder.org/ninjakx/3699d4c0efb0ac1d81636cf0e05eda2d
I am trying to integrate it with https://blockbuilder.org/ninjakx/fbbae54c3f4d8b2df8f9b981d46857b4.
When I will click on confirmed box then pie and histogram will show results related to hospitalized. In that above (dashboard) Those three graphs didn't have to cross filter, So I was able to write the logic. But I am confused about this one. How should I go about filtering it by "currentstatus" ("Hospitalized, "Recovered" etc)
I want this to take a "currentstatus" variable and return results related to it.
var group = dim.group(function(d) {
return binwidth * Math.floor(d/binwidth); });
So that I can do :
barChart
.height(300)
.width(500) //give it a width
.dimension(dim)
.group(group, currentstatus) //<------------------ Here
.......
I am thinking about creating three arrays for Hospitalized, Recovered, and Deceased Resp. But I think there might be some shorter solution than going this lengthy way.
EDIT:
I tried that too but I don't know how to count.
The result should be(calculated using pandas) :
gender currentstatus
F Deceased 31
Hospitalized 4225
Recovered 33
M Deceased 60
Hospitalized 7570
Recovered 50
But I get this:
0:
key: "M"
value: {Hospitalized: 7549, Deceased: 51, Recovered: 13}
__proto__: Object
1: {key: "NA", value: {…}}
2:
key: "F"
value: {Hospitalized: 4200, Deceased: 25, Recovered: 7}
__proto__: Object
length: 3
__proto__: Array(0)
How do I count? I know this below logic is wrong:
var group1 = pieTypeDimension.group().reduce(
function(p, v) { // add
p[v.currentstatus] = (p[v.currentstatus] || 0) + 1;
return p;
},
function(p, v) { // remove
p[v.currentstatus] -= 1;
return p;
},
function() { // initial
return {};
});
log("group1:::", group1.top(Infinity));
Tried this too:
var group1 = pieTypeDimension.group().reduce(
function(p, v) { // add
++p.count;
log("count:::", p.count);
p[v.currentstatus] = (p[v.currentstatus] || 0) + p.count;
return p;
},
function(p, v) { // remove
--p.count;
p[v.currentstatus] -= p.count;
return p;
},
function(p, v) { // initial
return {count:0};
});
and get this:
0:
key: "M"
value:
count: 7613
Hospitalized: 28769566
Deceased: 173237
Recovered: 39888
__proto__: Object
__proto__: Object
1:
key: "NA"
value: {count: 3, Hospitalized: 6}
__proto__: Object
2:
key: "F"
value: {count: 4232, Hospitalized: 8903341, Deceased: 43001, Recovered: 10686}
__proto__: Object
length: 3
__proto__: Array(0)
Edit:
I didn't take account of age bracket thing. Considering that Now it matches with the dc.js solution. So that logic is correct.
gender currentstatus
F Deceased 25
Hospitalized 4200
Recovered 7
M Deceased 51
Hospitalized 7549
Recovered 13
Name: currentstatus, dtype: int64
I will answer in a way that works with filtering, because that's the primary use case for dc.js.
I'd suggest going with the idiomatic crossfilter reduction for stacked charts, just without actually stacking anything.
From the FAQ:
var group = dimension.group().reduce(
function(p, v) { // add
p[v.type] = (p[v.type] || 0) + v.value;
return p;
},
function(p, v) { // remove
p[v.type] -= v.value;
return p;
},
function() { // initial
return {};
});
where type in your case is currentstatus.
This will give you a group where the values are objects keyed on status.
If you have every status for every X value, then each value object will have all status as keys; if not, some will be undefined.
Use valueAccessor to pull the field that you want for your chart, defaulting to 0 if undefined:
chart.valueAccessor(kv => kv.value[currentstatus] || 0)

Kendo Grid Sorting issues for numeric

I am using kendo grid to display data, but while sorting(ascending or descending) it's sorting perfectly for string values. But for numeric it's not sorting properly it's taking only first character to do sorting, not taking as string values even it's in numeric. How to solve this issue ?
You can use the gird column sortable.compare property to assign your own compare function.
Then what you are looking for is a Natural sort, like the one described here: http://web.archive.org/web/20130826203933/http://my.opera.com/GreyWyvern/blog/show.dml/1671288 and implemented here: http://www.davekoelle.com/files/alphanum.js
Here is a demo using a case insensitive version of the natural sort:
https://dojo.telerik.com/eReHUReH
function AlphaNumericCaseInsensitive(a, b) {
if (!a || a.length < 1) return -1;
var anum = Number(a);
var bnum = Number(b);
if (!isNaN(anum) && !isNaN(bnum)) {
return anum - bnum;
}
function chunkify(t) {
var tz = new Array();
var x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >= 48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
var aa = chunkify(a ? a.toLowerCase() : "");
var bb = chunkify(b ? b.toLowerCase() : "");
for (x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]), d = Number(bb[x]);
if (!isNaN(c) && !isNaN(d)) {
return c - d;
} else return (aa[x] > bb[x]) ? 1 : -1;
}
}
return aa.length - bb.length;
}
var dataSource = new kendo.data.DataSource({
data: [
{ id: 1, item: "item101" },
{ id: 2, item: "item2" },
{ id: 3, item: "item11" },
{ id: 4, item: "item1" }
]
});
$("#grid").kendoGrid({
dataSource: dataSource,
sortable: true,
columns: [{
field: "item",
sortable: {
compare: function(a, b) {
return AlphaNumericCaseInsensitive(a.item, b.item);
}
}
}]
});

adding function to loops through

I need to search in a big json nested collection which have unique IDs recursively. The collection contains key values or nested arrays which contains keys. Keys can be anywhere in the object. Keys can be number or string.
Please note: Key values are unique if they are not in array. If they are in array, the key duplicates per items in array. For example,
"WebData": {
WA1: 3, //not in array so unique
WA3: 2, so unique
WA3: "NEO",
WebGroup : [
{ Web1: 1, //duplicate Web1
Web2: 2
},
{ Web1: 2, //duplicate Web2
Web2: 2
}]
}
What I want:
I will pass an array of keys in different variations for example
Not in Arrays: I will pass key return either their values or sum for example:
function(["WA1",""WA3", "RAE1"],"notsum")
If I pass (not sum)
["WA1",""WA3", "RAE1"]
and the operation is not "sum", it should return an array of their values from the collection
[3,2,1]
If I pass the same but operation is sum)
function(["WA1",""WA3", "RAE1"],"sum")
["WA1",""WA3", "RAE1"]
it should return sum from the collection
return 6
If in Array: If the value to search are in the array means they duplicate, then it should return me sum or their individual values again For example
["WEB1","Web2"]
. It could either return me,
[7,1] //Again total of 3+4, 0+1 //see in example
or
[[3,4],[0,1]] //Because values are duplicate and in array, just collect them
I need to do in an elegant way:
Full example of JSON:
{
version: "1.0"
submission : "editing"
"WebData": {
WA1: 3,
WA3: 2,
WA3: "NEO",
WebGroup : [
{ Web1: 3,
Web2: 0
},
{ Web1: 4,
Web2: 1
}]
},
"NonWebData": {
NWA1: 3,
NWA2: "INP",
NWA3: 2,
},
"FormInputs": {
FM11: 3,
FM12: 1,
FM13: 2,
"RawData" : {
"RawOverview": {
"RAE1" : 1,
"RAE2" : 1,
},
"RawGroups":[
{
"name": "A1",
"id": "1",
"data":{
"AD1": 'period',
"AD2": 2,
"AD3": 2,
"transfers": [
{
"type": "in",
"TT1": 1,
"TT2": 2,
},
{
"type": "out",
"TT1": 1,
"TT2": 2,
}
]
}
},
{
"name": "A2",
"id": "2",
"data":{
"AD1": 'period',
"AD2": 2,
"AD3": 2,
"transfers": [
{
"type": "in",
"TT1": 1,
"TT2": 2,
},
{
"type": "out",
"TT1": 1,
"TT2": 2,
}
]
}
}
]
},
"Other":
{ O1: 1,
O2: 2,
O3: "hello"
},
"AddedBy": "name"
"AddedDate": "11/02/2019"
}
I am not able to write a function here, which can do this for me, my code is simply searching in this array, and I loop through to find it, which is I am sure not the correct way.
My code is not elegant, and I am using somehow repetitive functions. This is just one snippet, to find out the keys in one level. I want only 1 or 2 functions to do all this
function Search(paramKey, formDataArray) {
var varParams = [];
for (var key in formDataArray) {
if (formDataArray.hasOwnProperty(key)) {
var val = formDataArray[key];
for (var ikey in val) {
if (val.hasOwnProperty(ikey)) {
if (ikey == paramKey)
varParams.push(val[ikey]);
}
}
}
}
return varParams;
}
One more test case if in Array: to Return only single array of values, without adding. (Update - I achieved this through editing the code following part)
notsumsingle: function (target, key, value) {
if (target[key] === undefined) {
target[key] = value;
return;
}
target.push(value);
},
"groupData": [
{
"A1G1": 1,
"A1G2": 22,
"AIG3": 4,
"AIG4": "Rob"
},
{
"A1G1": 1,
"A1G2": 41,
"AIG3": 3,
"AIG4": "John"
},
{
"A1G1": 1,
"A1G2": 3,
"AIG3": 1,
"AIG4": "Andy"
}
],
perform(["AIG2",""AIG4"], "notsum")
It is returning me
[
[
22,
41,
3
]
],
[
[
"",
"Ron",
"Andy"
]
]
Instead, can I add one more variation "SingleArray" like "sum" and "notsum" and get the result as single Array.
[
22,
41,
3
]
[
"",
"Ron",
"Andy"
]
4th one, I asked, is it possible the function intelligent enough to pick up the sum of arrays or sum of individual fields automatically. for example, in your example, you have used "sum" and "total" to identify that.
console.log(perform(["WA1", "WA3", "RAE1"], "total")); // 6
console.log(perform(["Web1", "Web2"], "sum")); // [7, 1]
Can the function, just use "sum" and returns single or array based on if it finds array, return [7,1] if not return 6
5th : I found an issue in the code, if the json collection is added this way
perform(["RAE1"], "notsum") //[[1,1]]
perform(["RAE1"], "sum") //2
It returns [1, 1], or 2 although there is only one RAE1 defined and please note it is not an array [] so it should not be encoded into [[]] array, just the object key
"RawData" : {
"RawOverview": {
"RAE1" : 1,
"RAE2" : 1,
}
For making it easier, and to take the same interface for getting sums or not sums and a total, without any array, you could introduce another operation string total for getting the sum of all keys.
This approach takes an object for getting a function which either add an value to an array at the same index or stores the value at an specified index, which match the given keys array of the function.
For iterating the object, you could take the key/value pairs and iterate until no more object is found.
As result, you get an array, or the total sum of all items.
BTW, the keys of an object are case sensitive, for example 'WEB1' does not match 'Web1'.
function perform(keys, operation) {
function visit(object) {
Object
.entries(object)
.forEach(([k, v]) => {
if (k in indices) return fn(result, indices[k], v);
if (v && typeof v === 'object') visit(v);
});
}
var result = [],
indices = Object.assign({}, ...keys.map((k, i) => ({ [k]: i }))),
fn = {
notsum: function (target, key, value) {
if (target[key] === undefined) {
target[key] = value;
return;
}
if (!Array.isArray(target[key])) {
target[key] = [target[key]];
}
target[key].push(value);
},
sum: function (target, key, value) {
target[key] = (target[key] || 0) + value;
}
}[operation === 'total' ? 'sum' : operation];
visit(data);
return operation === 'total'
? result.reduce((a, b) => a + b)
: result;
}
var data = { version: "1.0", submission: "editing", WebData: { WA1: 3, WA3: 2, WAX: "NEO", WebGroup: [{ Web1: 3, Web2: 0 }, { Web1: 4, Web2: 1 }] }, NonWebData: { NWA1: 3, NWA2: "INP", NWA3: 2 }, FormInputs: { FM11: 3, FM12: 1, FM13: 2 }, RawData: { RawOverview: { RAE1: 1, RAE2: 1 }, RawGroups: [{ name: "A1", id: "1", data: { AD1: 'period', AD2: 2, AD3: 2, transfers: [{ type: "in", TT1: 1, TT2: 2 }, { type: "out", TT1: 1, TT2: 2 }] } }, { name: "A2", id: "2", data: { AD1: 'period', AD2: 2, AD3: 2, transfers: [{ type: "in", TT1: 1, TT2: 2 }, { type: "out", TT1: 1, TT2: 2 }] } }] }, Other: { O1: 1, O2: 2, O3: "hello" }, AddedBy: "name", AddedDate: "11/02/2019" };
console.log(perform(["WA1", "WA3", "RAE1"], "notsum")); // [3, 2, 1]
console.log(perform(["WA1", "WA3", "RAE1"], "total")); // 6
console.log(perform(["Web1", "Web2"], "sum")); // [7, 1]
console.log(perform(["Web1", "Web2"], "notsum")); // [[3, 4], [0, 1]]
.as-console-wrapper { max-height: 100% !important; top: 0; }

Showing sum of multiple values with amCharts

I would like to show sum of multiple values as one chart output with amCharts. I am using dataLoader with JSON to get the data. I know I have to create a function for but I couldn't understand how to get the data from the dataLoader to calculate
{
"balloonText": "[[title]] of [[valueAxis]]:[[value]]",
"lineThickness": 3,
"id": "sumValue",
"title": "sum Value",
"valueField": (function() {
var sumValues = "calculation";
return sumValues
}
this attempt is probably not correct but this is how I started
{
"balloonText": "[[title]] of [[valueAxis]]:[[value]]",
"lineThickness": 3,
"id": "LoadigTime",
"title": "Loadig Time",
"valueField": (function() {
var sumValues = (HomePageLoad + LoginToParametersLoad + ParametersLoad + AlarmsLoad + SwitchSideLoad + LoginToAdminLoad + AdminLoad) / 7;
return sumValues
})
}
valueField cannot be a function, only a string reference to a field in your data.
If the chart is meant to be displaying the sum of all of those fields in your data as a chart, simply add logic to your postProcess callback to create a new dataset containing your sums, e.g.
postProcess: function(data) {
var newData = [];
data.forEach(function(dataItem) {
var item = {
YOUR_CATEGORY_FIELD: dataItem.YOUR_CATEGORY_FIELD, //replace with your category field name
sum: 0
};
//loop through your item's keys and sum everything up, filtering out
//your category property
item.sum = Object.keys(dataItem).reduce(function(sum, key) {
if (key !== "YOUR_CATEGORY_FIELD") {
sum += dataItem[key]
}
return sum;
}, 0);
newData.push(item);
});
return newData;
},
// ...
graphs: [{
valueField: "sum",
// other props here
}]

Resources