Json list -
[
{
"date": "2022-10-10T09:53:40.835519+05:30",
"value": 10
},
{
"date": "2022-10-13T09:53:40.835519+05:30",
"value": 12
},
{
"date": "2022-10-13T10:53:40.835519+05:30",
"value": 15
},
{
"date": "2022-10-15T10:53:40.835519+05:30",
"value": 20
}
]
in above list if there are multiple dateTimes for same day ( ex. 2022-10-13 )
so how to mark 2022-10-13T10:53 date in object list as isLatestDateForSameDay=true as 2022-10-
13T10:53 is latest compare to 2022-10-13T09:53.
and if there is only one dateTime then it should also marked as isLatestDateForSameDay=true
ex. (2022-10-10T09:53:40.835519+05:30 and 2022-10-15T10:53:40.835519+05:30)
DataListItem class -
class DataListItem {
String date;
int value;
bool isLatestDate;
DataListItem({
required this.date,
required this.value,
this.isLatestDateForSameDay = false,
});
}
Expected list of Objects -
[
DataListItem(date: '2022-10-10T09:53:40.835519+05:30', value: 10, isLatestDateForSameDay: true),
DataListItem(date: '2022-10-13T09:53:40.835519+05:30', value: 12, isLatestDateForSameDay: false),
DataListItem(date: '2022-10-13T10:53:40.835519+05:30', value: 15, isLatestDateForSameDay: true),
DataListItem(date: '2022-10-15T10:53:40.835519+05:30', value: 20, isLatestDateForSameDay: true),
];
Lets assume your json is jsonData with collection package you can get what you want:
var grouped = groupBy(
jsonData,
(Map item) => (item['date'] as String).substring(0, 10),
);
List<DataListItem> result = [];
for (var element in grouped.entries) {
if (element.value.length == 1) {
result.add(DataListItem(
date: element.value.first['date'] as String,
value: element.value.first['value'] as int,
isLatestDate: true));
} else {
var latesItem = findLatestDate(element.value);
element.value.remove(latesItem);
result.add(DataListItem(
date: latesItem['date'] as String,
value: latesItem['value'] as int,
isLatestDate: true));
element.value.forEach((e) => result.add(DataListItem(
date: e['date'] as String,
value: e['value'] as int,
isLatestDate: false)));
}
}
Map<String, dynamic> findLatestDate(List<Map<String, dynamic>> dateList) {
Map<String, dynamic>? result;
for (var element in dateList) {
if (result == null) {
result = element;
} else {
DateTime resultDate =
DateFormat("yyyy-MM-ddThh:mm:ss").parse(result['date'] as String);
DateTime tempDate =
DateFormat("yyyy-MM-ddThh:mm:ss").parse(element['date'] as String);
if (tempDate.isAfter(resultDate)) {
result = element;
}
}
}
return result!;
}
for (var element in result) {
print("result= ${element.date} ${element.value} ${element.isLatestDate}");
// result= 2022-10-10T09:53:40.835519+05:30 10 true
// result= 2022-10-13T10:53:40.835519+05:30 15 true
// result= 2022-10-13T09:53:40.835519+05:30 12 false
// result= 2022-10-15T10:53:40.835519+05:30 20 true
}
also use intl for DateFormat.
Try sorting the list with DateTime.parse()
List<DataListItem> dataListItemlist = [];
list.sort(
(a, b) {
return DateTime.parse(a["date"]).compareTo(DateTime.parse(b["date"]));
},
);
List<String> repeatedDate = [];
for (var i = list.length - 1; i >= 0; i--) {
Map item = list[i];
DateTime date = DateTime.parse(item["date"]);
int day = date.day;
int month = date.month;
int year = date.year;
String formatedDate = "$day-$month-$year";
if (repeatedDate.contains(formatedDate)) {
dataListItemlist.add(
DataListItem(
date: item["date"],
value: item["value"],
isLatestDateForSameDay: false,
),
);
} else {
dataListItemlist.add(
DataListItem(
date: item["date"],
value: item["value"],
isLatestDateForSameDay: true,
),
);
repeatedDate.add(formatedDate);
}
}
I have employees, working_hours, & appointments table. with the following details:
Employees | working_hours | appointment
id, name | id, day, start_time, end_time, employeeable_id, employeeable_type | id, employee_id, start_date_time, end_date_time
Relation:
class Employee extends Model
{
public function workingHours()
{
return $this->morphMany(WorkingHour::class, 'employeeable');
}
}
class WorkingHour extends Model
{
public function employeeable()
{
return $this->morphTo();
}
}
class Appointment extends Model
{
public function employee()
{
return $this->belongsTo(Employee::class);
}
}
Employee A has the following working hours:
[
{ day: 1, start_time: '08:00:00', end_time: '17:00:00' },
...
{ day: 5, start_time: '08:00:00', end_time: '17:00:00 }
]
Employee A has an appointment on May 23, 2022 09:00:00 till 09:30:00 (each appointment duration is 30 minutes)
Question:
If admin requests for available slots from May 22, 2022 to June 1, 2022 for Employee A, I expect response like this:
[
{ '2022-05-22': ['08:00', '08:30', '09:00', ..., '17:00'] },
{ '2022-05-23': ['08:00', '08:30', '09:30'] } // 09:00 notice excluded.
...
{ '2022-06-01, [] }
]
How to define the above query? All I can think of is to loop every working hours time from employee A and check if the time is available or not.
I suggest you don't handle time with queries.
this is my solution:
public function index()
{
$appointment = [
'id' => 1,
'name' => 'Appointment 1',
'start_date_time' => '2022-05-23 09:00:00',
'end_date_time' => '2022-05-23 09:30:00'
];
// Employee A working hours
$workingHours = collect([
['day' => 1, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 2, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 3, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 4, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 5, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 6, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 0, 'start_time' => '08:00:00', 'end_time' => '17:00:00'], // carbon for sunday default is 0
]);
$dateArray = [];
$startDate = Carbon::parse('2022-05-22');
$endDate = Carbon::parse('2022-06-01');
while ($startDate->lte($endDate)) {
// seach for working hours that match the day of the week
$workingHour = (array) $workingHours->firstWhere('day', $startDate->dayOfWeek);
// generate time for each day
$times = $this->generateTimes($workingHour);
// extract date from appoint start date time
$appointmentDate = Carbon::parse($appointment['start_date_time'])->format('Y-m-d');
if ($appointmentDate === $startDate->format('Y-m-d')) {
// remove time according to appointment time
$times = $this->removeTime($times, $appointment);
}
// add time to date array
$dateArray[$startDate->format('Y-m-d')] = $times;
// increment date
$startDate->addDay();
}
dd($dateArray);
}
private function generateTimes(array $workingHour)
{
// the working time of the workers must be reduced by at least 1 hour.
// because there is no way for you to have an appointment on your end working time.
$startTime = Carbon::parse($workingHour['start_time']);
$endTime = Carbon::parse($workingHour['end_time'])->subHour();
$times = [];
while ($startTime->lte($endTime)) {
$times[] = $startTime->format('H:i');
$startTime->addMinutes(30);
}
return $times;
}
private function removeTime($times, $appointment)
{
$startTime = Carbon::parse($appointment['start_date_time']);
$endTime = Carbon::parse($appointment['end_date_time']);
$startTime = $startTime->format('H:i');
$endTime = $endTime->format('H:i');
$times = array_diff($times, [$startTime, $endTime]);
return $times;
}
I will check date with due date in data. If any due date <= date exists it is display true in html, If any due date <= date don't exists it is display false in html (show only 1 value). My data and my javascipt:
$scope.data = {
project: [
{
id: 1,
dueDate: '2021-10-30 00:00:00.000000',
},
{
id: 2,
dueDate: '2021-10-10 00:00:00.000000',
},
{
id: 3,
dueDate: '2021-10-20 00:00:00.000000',
},
{
id: 4,
dueDate: '2021-10-5 00:00:00.000000',
},
{
id: 5,
dueDate: '2021-10-2 00:00:00.000000',
},
]
};
// Format date
$scope.date = new Date().setHours(0, 0, 0, 0);
$scope.convertToDate = function(stringDate) {
var dateOut = new Date(stringDate);
return dateOut;
};
// Format Due Date
$scope.getDueDate = function(dateTime) {
return new Date(dateTime).setHours(0, 0, 0, 0);
};
My html:
<div ng-repeat="prj in data.project">
<div ng-if="date <= getDueDate(prj.dueDate)">
true
</div>
<div ng-if="date > getDueDate(prj.dueDate)">
false
</div>
</div>
I want to display with the above data is one value true
I have the following code which gets data from two sheets but can't figure out how update or add a new row in sheet "sumTransaction" where Category, Month & Year are equal.
For example in this example Expense 1, January, 2019 exists in the sumTransaction sheet so it should update the amount value by -3. Where Source A, January, 2019 and Other 1, March, 2019 do not exist in sumTransaction so they should be added to a new row.
function tableToObject() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const transactionSheet = ss.getSheetByName('Transactions')
const lastRow = transactionSheet.getLastRow()
const lastColumn = transactionSheet.getLastColumn()
const values = transactionSheet.getRange(1, 1, lastRow, lastColumn).getValues()
const [headers, ...originalData] = values.map(([,b,,d,e,,,,,,,,,,,p,q,r,s]) => [b,d,e,p,q,r,s])
const res = originalData.map(r => headers.reduce((o, h, j) => Object.assign(o, { [h]: r[j] }), {}))
console.log(res)
// GroupBy and Sum
const transactionGroup = [...res.reduce((r, o) => {
const key = o.Category + '_' + o.Month + '_' + o.Year
const item = r.get(key) || Object.assign({}, o, {
Amount: 0,
})
item.Amount += o.Amount
item.Key = key
return r.set(key, item)
}, new Map).values()]
console.log(transactionGroup)
const budgetValues = getBudget()
console.log(budgetValues)
// merge or add row
}
function getBudget(){
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sumSheet = ss.getSheetByName('sumTransacation')
const lastRow = sumSheet.getLastRow()
const lastColumn = sumSheet.getLastColumn()
const values = sumSheet.getRange(1, 1, lastRow, lastColumn).getValues()
const [headers, ...originalData] = values.map(([a,b,c,d,e,f]) => [a,b,c,d,e,f])
const res = originalData.map(r => headers.reduce((o, h, j) => Object.assign(o, { [h]: r[j] }), {}))
return res
}
transactionGroup Data
[ { Date: Fri Jan 04 2019 00:00:00 GMT-0700 (Mountain Standard Time),
Category: 'Source A',
Amount: 85,
Month: 'January',
Year: 2019,
Group: 'COGS',
Debit: 'Credit',
Key: 'Source A_January_2019' },
{ Date: Mon Feb 25 2019 00:00:00 GMT-0700 (Mountain Standard Time),
Category: 'Expense 1',
Amount: -3,
Month: 'February',
Year: 2019,
Group: 'Expense',
Debit: 'Debit',
Key: 'Expense 1_February_2019' },
{ Date: Tue Mar 26 2019 00:00:00 GMT-0600 (Mountain Daylight Time),
Category: 'Other 1',
Amount: -4,
Month: 'March',
Year: 2019,
Group: 'Other',
Debit: 'Debit',
Key: 'Other 1_March_2019'
} ]
budgetValues Data
[ { Category: 'Expense 1',
Month: 'January',
Year: 2019,
Group: 'COGS',
Amount: 10,
'Debit/Credit': '' },
{ Category: 'Expense 2',
Month: 'January',
Year: 2019,
Group: 'COGS',
Amount: 10,
'Debit/Credit': '' } ]
Sample Image of sumTransactions Sheet ( i.e. before script )
Sample Image of sumTransactions Sheet ( i.e. after script )
I believe your goal is as follows.
There are 2 sheets which are the source sheet Transactions and the destination sheet sumTransacation.
You want to check the duplicated values between the source and destination sheets. At that time, you want to check the columns "A" to "C" on the destination sheet. So from your sample values, you want to check the values of Category, Month, and Year.
From your explanation,
When I saw your values of transactionGroup Data and budgetValues Data, Category: 'Expense 1' of transactionGroup Data is Month: 'February',. And Category: 'Expense 1' of budgetValues Data is Month: 'January',. When I saw the images of i.e. before script and i.e. after script, Category: 'Expense 1' of transactionGroup Data is removed. In this case, I thought that you might want to add the value of Category: 'Expense 1' of transactionGroup Data to the destination sheet.
When my understanding is correct, how about the following sample script?
Sample script:
I added the script's flow in the script as the comment.
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
// 1. Retrieve values from destination sheet.
const dst = ss.getSheetByName('sumTransacation');
const [headers, ...dstVal] = dst.getDataRange().getValues();
// 2. Retrieve values from source sheet.
const src = ss.getSheetByName('Transactions');
const [srcHead, ...srcVal] = src.getDataRange().getValues();
const srcIdx = headers.reduce((ar, h) => {
const temp = srcHead.indexOf(h);
if (temp > -1) ar.push(temp);
return ar
}, []);
const srcValues = srcVal.map(r => srcIdx.map(i => r[i]));
// 3. Update values of destination sheet.
const obj1 = srcValues.reduce((o, r) => Object.assign(o, {[`${r[0] + r[1] + r[2]}`]: r}), {});
const values1 = dstVal.map(r => {
const temp = obj1[r[0] + r[1] + r[2]];
if (temp) {
return r.slice(0, 4).concat([r[4] + temp[4], r[5]]);
}
return r;
});
// 4. Added new values of source sheet.
const obj2 = dstVal.reduce((o, r) => Object.assign(o, {[`${r[0] + r[1] + r[2]}`]: r}), {});
const values2 = srcValues.reduce((ar, r) => {
if (!obj2[r[0] + r[1] + r[2]]) ar.push(r);
return ar;
}, []);
const values = [headers, ...values1, ...values2];
// 5. Update the destination sheet using new values.
dst.clearContents().getRange(1, 1, values.length, values[0].length).setValues(values);
}
References:
reduce()
map()
Edit:
When I saw your sample Spreadsheet, I noticed that your spreadsheet is different from your sample images. I think that this is the reason of your issue. So for your sample Spreadsheet, I added one more sample script as follows.
Sample script:
function sample2() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
// 1. Retrieve values from destination sheet.
const dst = ss.getSheetByName('sumTransacation');
const [headers, ...dstVal] = dst.getDataRange().getValues();
// 2. Retrieve values from source sheet.
const src = ss.getSheetByName('Transactions');
const [srcHead, ...srcVal] = src.getDataRange().getValues().map(([,b,,d,e,,,,,,,,,,,p,q,r,s]) => [b,d,e,p,q,r,s])
const srcIdx = headers.reduce((ar, h) => {
const temp = srcHead.indexOf(h);
if (temp > -1) {
ar.push(temp);
} else {
ar.push("");
}
return ar
}, []);
const srcValues = srcVal.map(r => srcIdx.map(i => r[i]));
// 3. Update values of destination sheet.
const obj1 = srcValues.reduce((o, r) => Object.assign(o, {[`${r[0] + r[1] + r[2]}`]: r}), {});
const values1 = dstVal.map(r => {
const temp = obj1[r[0] + r[1] + r[2]];
if (temp) {
return r.slice(0, 4).concat([r[4] + temp[4], r[5]]);
}
return r;
});
// 4. Added new values of source sheet.
const obj2 = dstVal.reduce((o, r) => Object.assign(o, {[`${r[0] + r[1] + r[2]}`]: r}), {});
const values2 = srcValues.reduce((ar, r) => {
if (!obj2[r[0] + r[1] + r[2]]) ar.push(r);
return ar;
}, []);
const values = [headers, ...values1, ...values2];
dst.clearContents().getRange(1, 1, values.length, values[0].length).setValues(values);
}
In your sample Spreadsheet, the values of "Month" of "Transactions" is different from that of "sumTransacation" sheet. But, unfortunately, I cannot know your actual format. So, when you want to compare the values, how about changing the format as the same format? Please be careful this.
I want to get sum of column from two different tables in sequilize.
I want to accurate totalpaid, refunded & refundable field, which vary according to group by, I'm not be able to resolve it.
//Some pre-desined variables
var totalPaidQueryStr = '(CASE WHEN (SUM(inv_payment_record_invoices.payment)) IS NULL THEN 0 ELSE (SUM(inv_payment_record_invoices.payment)) END)';
var totalPaidQuery = [Sequelize.literal(totalPaidQueryStr), 'totalpaid']; //Get the total paid amount till date;
var refundedQueryStr = '(CASE WHEN (SUM(inv_payment_record_refunds.amount)) IS NULL THEN 0 ELSE (SUM(inv_payment_record_refunds.amount)) END)';
var refundedQuery = [Sequelize.literal(refundedQueryStr), 'refunded']; //Get the total paid amount till date
var refundableQueryStr = `(inv_payment_records.amount - (${totalPaidQueryStr} + ${refundedQueryStr}))`;
var refundableQuery = [Sequelize.literal(refundableQueryStr), 'refundable']; //Get the total due amount
return InvPaymentRecords.findOne({
attributes: [
'customer_id',
'amount',
'company_currency_id',
'exchange_rate',
totalPaidQuery, //Want to accurate sum
refundedQuery, //Want to accurate sum
refundableQuery
],
where: {
'id': payment_record_id,
'company_id': company_id
},
include: [
{
model: InvPaymentRecordInvoices,
require: false,
attributes: [],
},
{
model: InvPaymentRecordRefund,
require: false,
attributes: [],
}
],
group: [
//'inv_payment_records.id',
//'inv_payment_record_invoices.id',
//'inv_payment_record_refunds.id'
]
}).then(iprdata => {
return sequelize.Promise.resolve(iprdata);
}).catch(error => {
return sequelize.Promise.reject(error);
})