Compare commits
50 Commits
79d14a2023
...
d9b45297ab
| Author | SHA1 | Date |
|---|---|---|
|
|
d9b45297ab | |
|
|
7d3dd1bc2b | |
|
|
bc0c4ea437 | |
|
|
e1742b9d0c | |
|
|
9c9f6c1c95 | |
|
|
5914ed1944 | |
|
|
a27047bc4a | |
|
|
9ff8890796 | |
|
|
8b65e39d5c | |
|
|
de866d0747 | |
|
|
ec9b566f07 | |
|
|
6fe280dfa2 | |
|
|
5ec1941e4a | |
|
|
fbe0a3fbbc | |
|
|
b9061bab3f | |
|
|
9c6fafb741 | |
|
|
5ca3c9dee2 | |
|
|
37ed3b5369 | |
|
|
1304586f9f | |
|
|
370aa24b6f | |
|
|
b6885903d7 | |
|
|
ea9fb09ff1 | |
|
|
e34564041e | |
|
|
6dc6c386d2 | |
|
|
d761cc8d40 | |
|
|
e6cbbd679a | |
|
|
3f8aa89705 | |
|
|
bd4cfee509 | |
|
|
45c1f46bc6 | |
|
|
2a4ea19178 | |
|
|
12aa59f401 | |
|
|
5c1d136bca | |
|
|
df8fdd923e | |
|
|
7ed247d057 | |
|
|
29b5a22a6d | |
|
|
4fb6f3a657 | |
|
|
f0a4bfdf90 | |
|
|
fe5f1e52b3 | |
|
|
3d3fbd518f | |
|
|
ff0a7ce5e4 | |
|
|
177655da30 | |
|
|
60fa39b4a7 | |
|
|
9958cc481f | |
|
|
dd418d2ca0 | |
|
|
fbf9830c5d | |
|
|
5677b61e83 | |
|
|
28cc9ce57a | |
|
|
8655376460 | |
|
|
ebbfb0c445 | |
|
|
457867f3b0 |
|
|
@ -61,111 +61,116 @@ class AttendanceReport(models.Model):
|
||||||
# Define the query
|
# Define the query
|
||||||
query = """
|
query = """
|
||||||
WITH date_range AS (
|
WITH date_range AS (
|
||||||
SELECT generate_series(
|
SELECT generate_series(
|
||||||
%s::date,
|
%s::date,
|
||||||
%s::date,
|
%s::date,
|
||||||
interval '1 day'
|
interval '1 day'
|
||||||
)::date AS date
|
)::date AS date
|
||||||
),
|
),
|
||||||
employee_dates AS (
|
employee_dates AS (
|
||||||
SELECT
|
SELECT
|
||||||
emp.id AS employee_id,
|
emp.id AS employee_id,
|
||||||
emp.name AS employee_name,
|
emp.name AS employee_name,
|
||||||
dr.date,
|
dr.date,
|
||||||
TO_CHAR(dr.date, 'Day') AS day_name,
|
TO_CHAR(dr.date, 'Day') AS day_name,
|
||||||
EXTRACT(WEEK FROM dr.date) AS week_number,
|
EXTRACT(WEEK FROM dr.date) AS week_number,
|
||||||
TO_CHAR(date_trunc('week', dr.date), 'MON DD') || ' - ' ||
|
TO_CHAR(date_trunc('week', dr.date), 'MON DD') || ' - ' ||
|
||||||
TO_CHAR(date_trunc('week', dr.date) + interval '6 days', 'MON DD') AS week_range,
|
TO_CHAR(date_trunc('week', dr.date) + interval '6 days', 'MON DD') AS week_range,
|
||||||
dep.name->>'en_US' AS department
|
dep.name->>'en_US' AS department
|
||||||
FROM
|
FROM
|
||||||
hr_employee emp
|
hr_employee emp
|
||||||
CROSS JOIN
|
CROSS JOIN
|
||||||
date_range dr
|
date_range dr
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
hr_department dep ON emp.department_id = dep.id
|
hr_department dep ON emp.department_id = dep.id
|
||||||
WHERE
|
WHERE
|
||||||
emp.active = true
|
emp.active = true
|
||||||
""" + (" AND " + " AND ".join(emp_date_conditions) if emp_date_conditions else "") + """
|
""" + (" AND " + " AND ".join(emp_date_conditions) if emp_date_conditions else "") + """
|
||||||
),
|
),
|
||||||
daily_checkins AS (
|
daily_checkins AS (
|
||||||
SELECT
|
SELECT
|
||||||
emp.id,
|
emp.id,
|
||||||
emp.name,
|
emp.name,
|
||||||
DATE(at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata') AS date,
|
DATE(at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata') AS date,
|
||||||
at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' AS check_in,
|
at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' AS check_in,
|
||||||
at.check_out AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' AS check_out,
|
at.check_out AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' AS check_out,
|
||||||
at.worked_hours,
|
at.worked_hours,
|
||||||
ROW_NUMBER() OVER (PARTITION BY emp.id, DATE(at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata') ORDER BY at.check_in) AS first_checkin_row,
|
ROW_NUMBER() OVER (PARTITION BY emp.id, DATE(at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata') ORDER BY at.check_in) AS first_checkin_row,
|
||||||
ROW_NUMBER() OVER (PARTITION BY emp.id, DATE(at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata') ORDER BY at.check_in DESC) AS last_checkout_row,
|
ROW_NUMBER() OVER (PARTITION BY emp.id, DATE(at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata') ORDER BY at.check_in DESC) AS last_checkout_row,
|
||||||
dep.name->>'en_US' AS department
|
dep.name->>'en_US' AS department,
|
||||||
FROM
|
LEAD(at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata') OVER (PARTITION BY emp.id, DATE(at.check_in AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata') ORDER BY at.check_in) AS next_check_in
|
||||||
hr_attendance at
|
FROM
|
||||||
LEFT JOIN
|
hr_attendance at
|
||||||
hr_employee emp ON at.employee_id = emp.id
|
LEFT JOIN
|
||||||
LEFT JOIN
|
hr_employee emp ON at.employee_id = emp.id
|
||||||
hr_department dep ON emp.department_id = dep.id
|
LEFT JOIN
|
||||||
WHERE
|
hr_department dep ON emp.department_id = dep.id
|
||||||
""" + " AND ".join(checkin_conditions) + """
|
WHERE
|
||||||
),
|
""" + " AND ".join(checkin_conditions) + """
|
||||||
attendance_summary AS (
|
),
|
||||||
SELECT
|
attendance_summary AS (
|
||||||
id,
|
SELECT
|
||||||
name,
|
id,
|
||||||
date,
|
name,
|
||||||
MAX(CASE WHEN first_checkin_row = 1 THEN check_in END) AS first_check_in,
|
date,
|
||||||
MAX(CASE WHEN last_checkout_row = 1 THEN check_out END) AS last_check_out,
|
MAX(CASE WHEN first_checkin_row = 1 THEN check_in END) AS first_check_in,
|
||||||
SUM(worked_hours) AS total_worked_hours,
|
MAX(CASE WHEN last_checkout_row = 1 THEN check_out END) AS last_check_out,
|
||||||
department
|
SUM(worked_hours) AS total_worked_hours,
|
||||||
FROM
|
-- 👇 Calculate total break time (sum of gaps between check_out and next check_in)
|
||||||
daily_checkins
|
SUM(
|
||||||
GROUP BY
|
EXTRACT(EPOCH FROM (next_check_in - check_out)) / 3600
|
||||||
id, name, date, department
|
) FILTER (WHERE next_check_in IS NOT NULL AND check_out IS NOT NULL) AS break_hours,
|
||||||
),
|
department
|
||||||
leave_data AS (
|
FROM
|
||||||
SELECT
|
daily_checkins
|
||||||
hl.employee_id,
|
GROUP BY
|
||||||
hl.date_from AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' AS leave_start,
|
id, name, date, department
|
||||||
hl.date_to AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' AS leave_end,
|
),
|
||||||
hlt.name->>'en_US' AS leave_type,
|
leave_data AS (
|
||||||
hl.request_unit_half AS is_half_day,
|
SELECT
|
||||||
hl.request_date_from,
|
hl.employee_id,
|
||||||
hl.request_date_to
|
hl.date_from AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' AS leave_start,
|
||||||
FROM
|
hl.date_to AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' AS leave_end,
|
||||||
hr_leave hl
|
hlt.name->>'en_US' AS leave_type,
|
||||||
JOIN
|
hl.request_unit_half AS is_half_day,
|
||||||
hr_leave_type hlt ON hl.holiday_status_id = hlt.id
|
hl.request_date_from,
|
||||||
WHERE
|
hl.request_date_to
|
||||||
hl.state IN ('validate', 'confirm', 'validate1')
|
FROM
|
||||||
AND (hl.date_from, hl.date_to) OVERLAPS (%s::timestamp, %s::timestamp)
|
hr_leave hl
|
||||||
)
|
JOIN
|
||||||
SELECT
|
hr_leave_type hlt ON hl.holiday_status_id = hlt.id
|
||||||
ed.employee_id AS id,
|
WHERE
|
||||||
ed.employee_name AS name,
|
hl.state IN ('validate', 'confirm', 'validate1')
|
||||||
ed.date,
|
AND (hl.date_from, hl.date_to) OVERLAPS (%s::timestamp, %s::timestamp)
|
||||||
'Week ' || ed.week_number || ' (' || ed.week_range || ')' AS week_info,
|
)
|
||||||
TRIM(ed.day_name) AS day_name,
|
SELECT
|
||||||
COALESCE(ats.first_check_in, NULL) AS first_check_in,
|
ed.employee_id AS id,
|
||||||
COALESCE(ats.last_check_out, NULL) AS last_check_out,
|
ed.employee_name AS name,
|
||||||
COALESCE(ats.total_worked_hours, 0) AS total_worked_hours,
|
ed.date,
|
||||||
ed.department,
|
'Week ' || ed.week_number || ' (' || ed.week_range || ')' AS week_info,
|
||||||
CASE
|
TRIM(ed.day_name) AS day_name,
|
||||||
WHEN ld.leave_type IS NOT NULL AND ld.is_half_day THEN 'on Half day ' || ld.leave_type
|
COALESCE(ats.first_check_in, NULL) AS first_check_in,
|
||||||
WHEN ld.leave_type IS NOT NULL THEN 'on ' || ld.leave_type
|
COALESCE(ats.last_check_out, NULL) AS last_check_out,
|
||||||
WHEN ats.first_check_in IS NOT NULL THEN 'Present'
|
COALESCE(ats.total_worked_hours, 0) AS total_worked_hours,
|
||||||
ELSE 'NA'
|
COALESCE(ats.break_hours, 0) AS total_break_hours,
|
||||||
END AS status
|
ed.department,
|
||||||
FROM
|
CASE
|
||||||
employee_dates ed
|
WHEN ld.leave_type IS NOT NULL AND ld.is_half_day THEN 'on Half day ' || ld.leave_type
|
||||||
LEFT JOIN
|
WHEN ld.leave_type IS NOT NULL THEN 'on ' || ld.leave_type
|
||||||
attendance_summary ats ON ed.employee_id = ats.id AND ed.date = ats.date
|
WHEN ats.first_check_in IS NOT NULL THEN 'Present'
|
||||||
LEFT JOIN
|
ELSE 'NA'
|
||||||
leave_data ld ON ed.employee_id = ld.employee_id
|
END AS status
|
||||||
AND ed.date >= DATE(ld.leave_start)
|
FROM
|
||||||
AND ed.date <= DATE(ld.leave_end)
|
employee_dates ed
|
||||||
ORDER BY
|
LEFT JOIN
|
||||||
ed.employee_id, ed.date;
|
attendance_summary ats ON ed.employee_id = ats.id AND ed.date = ats.date
|
||||||
|
LEFT JOIN
|
||||||
|
leave_data ld ON ed.employee_id = ld.employee_id
|
||||||
|
AND ed.date >= DATE(ld.leave_start)
|
||||||
|
AND ed.date <= DATE(ld.leave_end)
|
||||||
|
ORDER BY
|
||||||
|
ed.employee_id, ed.date;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Combine all parameters in the correct order:
|
# Combine all parameters in the correct order:
|
||||||
# 1. date_range params (start_date_str, end_date_str)
|
# 1. date_range params (start_date_str, end_date_str)
|
||||||
# 2. employee_dates params (emp_date_params)
|
# 2. employee_dates params (emp_date_params)
|
||||||
|
|
@ -196,6 +201,7 @@ class AttendanceReport(models.Model):
|
||||||
'check_in': r['first_check_in'],
|
'check_in': r['first_check_in'],
|
||||||
'check_out': r['last_check_out'],
|
'check_out': r['last_check_out'],
|
||||||
'worked_hours': float(r['total_worked_hours']) if r['total_worked_hours'] is not None else 0.0,
|
'worked_hours': float(r['total_worked_hours']) if r['total_worked_hours'] is not None else 0.0,
|
||||||
|
'break_hours': float(r['total_break_hours']) if r['total_break_hours'] is not None else 0.0,
|
||||||
'status': r['status']
|
'status': r['status']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -213,7 +219,6 @@ class AttendanceReport(models.Model):
|
||||||
attendance_data = self.get_attendance_report(department_id, employee_id, start_date, end_date)
|
attendance_data = self.get_attendance_report(department_id, employee_id, start_date, end_date)
|
||||||
if not attendance_data:
|
if not attendance_data:
|
||||||
raise UserError("No data to export!")
|
raise UserError("No data to export!")
|
||||||
|
|
||||||
# Create workbook and sheet
|
# Create workbook and sheet
|
||||||
workbook = xlwt.Workbook(encoding='utf-8')
|
workbook = xlwt.Workbook(encoding='utf-8')
|
||||||
sheet = workbook.add_sheet('Attendance Report')
|
sheet = workbook.add_sheet('Attendance Report')
|
||||||
|
|
@ -281,28 +286,26 @@ class AttendanceReport(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set column widths (in units of 1/256 of a character width)
|
# Set column widths (in units of 1/256 of a character width)
|
||||||
col_widths = [6000, 8000, 7000, 3000, 4000, 5000, 5000, 4000, 5000]
|
col_widths = [6000, 8000, 7000, 3000, 4000, 5000, 5000, 4000, 4000, 5000]
|
||||||
for i, width in enumerate(col_widths):
|
for i, width in enumerate(col_widths):
|
||||||
sheet.col(i).width = width
|
sheet.col(i).width = width
|
||||||
|
|
||||||
# Write title
|
# Write title
|
||||||
sheet.write_merge(0, 0, 0, 8, 'ATTENDANCE REPORT', title_style)
|
sheet.write_merge(0, 0, 0, 9, 'ATTENDANCE REPORT', title_style)
|
||||||
|
|
||||||
# Write date range
|
# Write date range
|
||||||
date_range = f"From: {start_date} To: {end_date}"
|
date_range = f"From: {start_date} To: {end_date}"
|
||||||
sheet.write_merge(1, 1, 0, 8, date_range, xlwt.easyxf(
|
sheet.write_merge(1, 1, 0, 9, date_range, xlwt.easyxf(
|
||||||
'font: italic on; align: horiz center'
|
'font: italic on; align: horiz center'
|
||||||
))
|
))
|
||||||
|
|
||||||
# Write headers
|
# Write headers
|
||||||
headers = [
|
headers = [
|
||||||
'Department', 'Employee Name','Week', 'Date', 'Day',
|
'Department', 'Employee Name','Week', 'Date', 'Day',
|
||||||
'Check-in', 'Check-out', 'Worked Hours', 'Status'
|
'Check-in', 'Check-out', 'Worked Hours', 'Break Hours', 'Status'
|
||||||
]
|
]
|
||||||
|
|
||||||
for col_num, header in enumerate(headers):
|
for col_num, header in enumerate(headers):
|
||||||
sheet.write(2, col_num, header, header_style)
|
sheet.write(2, col_num, header, header_style)
|
||||||
|
|
||||||
# Write data rows
|
# Write data rows
|
||||||
current_employee = None
|
current_employee = None
|
||||||
for row_num, record in enumerate(attendance_data, start=3):
|
for row_num, record in enumerate(attendance_data, start=3):
|
||||||
|
|
@ -345,11 +348,16 @@ class AttendanceReport(models.Model):
|
||||||
else:
|
else:
|
||||||
sheet.write(row_num, 7, str(record['worked_hours']), data_style)
|
sheet.write(row_num, 7, str(record['worked_hours']), data_style)
|
||||||
|
|
||||||
sheet.write(row_num, 8, record['status'], status_style)
|
# Break hours formatting
|
||||||
|
if isinstance(record['break_hours'], (float, int)):
|
||||||
|
sheet.write(row_num, 8, float(record['break_hours']), hours_style)
|
||||||
|
else:
|
||||||
|
sheet.write(row_num, 8, str(record['break_hours']), data_style)
|
||||||
|
|
||||||
|
sheet.write(row_num, 9, record['status'], status_style)
|
||||||
# Add freeze panes (headers will stay visible when scrolling)
|
# Add freeze panes (headers will stay visible when scrolling)
|
||||||
sheet.set_panes_frozen(True)
|
sheet.set_panes_frozen(True)
|
||||||
sheet.set_horz_split_pos(4) # After row 3 (headers)
|
sheet.set_horz_split_pos(3) # After row 3 (headers)
|
||||||
sheet.set_vert_split_pos(0) # No vertical split
|
sheet.set_vert_split_pos(0) # No vertical split
|
||||||
|
|
||||||
# Save to buffer
|
# Save to buffer
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ export default class AttendanceReport extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateReport() {
|
async generateReport() {
|
||||||
|
debugger;
|
||||||
let { startDate, endDate, selectedEmployeeIds } = this.state;
|
let { startDate, endDate, selectedEmployeeIds } = this.state;
|
||||||
startDate = $('#from_date').val()
|
startDate = $('#from_date').val()
|
||||||
endDate = $('#to_date').val()
|
endDate = $('#to_date').val()
|
||||||
|
|
@ -231,7 +231,7 @@ export default class AttendanceReport extends Component {
|
||||||
// Fetch the attendance data based on the date range and selected employees
|
// Fetch the attendance data based on the date range and selected employees
|
||||||
// const attendanceData = await this.orm.searchRead('hr.attendance', domain, ['employee_id', 'check_in', 'check_out', 'worked_hours']);
|
// const attendanceData = await this.orm.searchRead('hr.attendance', domain, ['employee_id', 'check_in', 'check_out', 'worked_hours']);
|
||||||
const attendanceData = await this.orm.call('attendance.report','get_attendance_report',[$('#dept').val(),$('#emp').val(),startDate,endDate]);
|
const attendanceData = await this.orm.call('attendance.report','get_attendance_report',[$('#dept').val(),$('#emp').val(),startDate,endDate]);
|
||||||
|
debugger;
|
||||||
// Group data by employee_id
|
// Group data by employee_id
|
||||||
const rawGroups = this.groupDataByEmployee(attendanceData);
|
const rawGroups = this.groupDataByEmployee(attendanceData);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@
|
||||||
<th>Check In</th>
|
<th>Check In</th>
|
||||||
<th>Check Out</th>
|
<th>Check Out</th>
|
||||||
<th>Worked Hours</th>
|
<th>Worked Hours</th>
|
||||||
|
<th>Break Hours</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -78,7 +79,16 @@
|
||||||
<td><t t-esc="data.day_name"/></td>
|
<td><t t-esc="data.day_name"/></td>
|
||||||
<td><t t-esc="data.check_in"/></td>
|
<td><t t-esc="data.check_in"/></td>
|
||||||
<td><t t-esc="data.check_out"/></td>
|
<td><t t-esc="data.check_out"/></td>
|
||||||
<td><t t-esc="data.worked_hours"/></td>
|
<td>
|
||||||
|
<t t-set="hours" t-value="Math.floor(data.worked_hours)"/>
|
||||||
|
<t t-set="minutes" t-value="Math.round((data.worked_hours - hours) * 60)"/>
|
||||||
|
<t t-esc="hours"/>:<t t-esc="minutes >= 10 ? minutes : '0' + minutes"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<t t-set="hours" t-value="Math.floor(data.break_hours)"/>
|
||||||
|
<t t-set="minutes" t-value="Math.round((data.break_hours - hours) * 60)"/>
|
||||||
|
<t t-esc="hours"/>:<t t-esc="minutes >= 10 ? minutes : '0' + minutes"/>
|
||||||
|
</td>
|
||||||
<td><t t-esc="data.status"/></td>
|
<td><t t-esc="data.status"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,12 @@
|
||||||
'version': '0.1',
|
'version': '0.1',
|
||||||
|
|
||||||
# any module necessary for this one to work correctly
|
# any module necessary for this one to work correctly
|
||||||
|
|
||||||
'depends': ['base','hr','account','mail','hr_skills', 'hr_contract'],
|
'depends': ['base','hr','account','mail','hr_skills', 'hr_contract'],
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# always loaded
|
# always loaded
|
||||||
'data': [
|
'data': [
|
||||||
'security/security.xml',
|
'security/security.xml',
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,8 @@ class HRJobRecruitment(models.Model):
|
||||||
rec.submission_status = 'zero'
|
rec.submission_status = 'zero'
|
||||||
|
|
||||||
|
|
||||||
|
experience = fields.Many2one('candidate.experience', string="Experience")
|
||||||
|
|
||||||
@api.depends('application_ids.submitted_to_client')
|
@api.depends('application_ids.submitted_to_client')
|
||||||
def _compute_no_of_submissions(self):
|
def _compute_no_of_submissions(self):
|
||||||
counts = dict(self.env['hr.applicant']._read_group(
|
counts = dict(self.env['hr.applicant']._read_group(
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ Dashboard Ninja v16.0,
|
||||||
'ks_dashboard_ninja/static/src/css/ks_toggle_icon.css',
|
'ks_dashboard_ninja/static/src/css/ks_toggle_icon.css',
|
||||||
'ks_dashboard_ninja/static/src/css/ks_flower_view.css',
|
'ks_dashboard_ninja/static/src/css/ks_flower_view.css',
|
||||||
'ks_dashboard_ninja/static/src/css/ks_map_view.css',
|
'ks_dashboard_ninja/static/src/css/ks_map_view.css',
|
||||||
|
'ks_dashboard_ninja/static/src/css/ks_profile.css',
|
||||||
'ks_dashboard_ninja/static/src/css/ks_funnel_view.css',
|
'ks_dashboard_ninja/static/src/css/ks_funnel_view.css',
|
||||||
'ks_dashboard_ninja/static/src/css/ks_dashboard_options.css',
|
'ks_dashboard_ninja/static/src/css/ks_dashboard_options.css',
|
||||||
'/ks_dashboard_ninja/static/lib/js/gridstack-h5.js',
|
'/ks_dashboard_ninja/static/lib/js/gridstack-h5.js',
|
||||||
|
|
|
||||||
|
|
@ -387,7 +387,8 @@ class KsDashboardNinjaItems(models.Model):
|
||||||
('ks_to_do', 'To Do'),
|
('ks_to_do', 'To Do'),
|
||||||
('ks_map_view', 'Map View'),
|
('ks_map_view', 'Map View'),
|
||||||
('ks_funnel_chart', 'Funnel Chart'),
|
('ks_funnel_chart', 'Funnel Chart'),
|
||||||
('ks_bullet_chart', 'Bullet Chart')
|
('ks_bullet_chart', 'Bullet Chart'),
|
||||||
|
('ks_profile', 'Profile Chart'),
|
||||||
], default=lambda self: self._context.get('ks_dashboard_item_type',
|
], default=lambda self: self._context.get('ks_dashboard_item_type',
|
||||||
'ks_tile'), required=True,
|
'ks_tile'), required=True,
|
||||||
string="Dashboard Item Type",
|
string="Dashboard Item Type",
|
||||||
|
|
@ -639,6 +640,7 @@ class KsDashboardNinjaItems(models.Model):
|
||||||
help="Display the total sum of each legends as it grows with times")
|
help="Display the total sum of each legends as it grows with times")
|
||||||
ks_radial_preview = fields.Char(string="Radial Preview", default="Radial Preview")
|
ks_radial_preview = fields.Char(string="Radial Preview", default="Radial Preview")
|
||||||
ks_map_preview = fields.Char(string="Map Preview", default="Map Preview")
|
ks_map_preview = fields.Char(string="Map Preview", default="Map Preview")
|
||||||
|
ks_profile_preview = fields.Char(string="Profile Preview", default="Profile Preview")
|
||||||
ks_partners_map = fields.Char(compute="_compute_map_partners")
|
ks_partners_map = fields.Char(compute="_compute_map_partners")
|
||||||
ks_country_id = fields.Many2one('res.country', string="Country")
|
ks_country_id = fields.Many2one('res.country', string="Country")
|
||||||
ks_country_code = fields.Char(related="ks_country_id.code", store=True)
|
ks_country_code = fields.Char(related="ks_country_id.code", store=True)
|
||||||
|
|
@ -694,6 +696,11 @@ class KsDashboardNinjaItems(models.Model):
|
||||||
ks_three_d = fields.Boolean(string='3D View', default=False)
|
ks_three_d = fields.Boolean(string='3D View', default=False)
|
||||||
|
|
||||||
|
|
||||||
|
@api.onchange('ks_dashboard_item_type')
|
||||||
|
def onchange_ks_dashboard_item_type(self):
|
||||||
|
for rec in self:
|
||||||
|
if rec.ks_dashboard_item_type == 'ks_profile':
|
||||||
|
rec.ks_model_id = self.env['ir.model'].sudo().search([('model','=','hr.employee')],limit=1)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def create_ai_dash(self, data, ks_dash_id, model):
|
def create_ai_dash(self, data, ks_dash_id, model):
|
||||||
|
|
@ -4533,7 +4540,9 @@ class KsDashboardItemsActions(models.Model):
|
||||||
('ks_radar_view', 'Radar View'),
|
('ks_radar_view', 'Radar View'),
|
||||||
('ks_flower_view', 'Flower View'),
|
('ks_flower_view', 'Flower View'),
|
||||||
('ks_funnel_chart', 'Funnel Chart'),
|
('ks_funnel_chart', 'Funnel Chart'),
|
||||||
('ks_bullet_chart', 'Bullet Chart')],
|
('ks_bullet_chart', 'Bullet Chart'),
|
||||||
|
('ks_profile', 'Profile Chart')
|
||||||
|
],
|
||||||
string="Item Type")
|
string="Item Type")
|
||||||
|
|
||||||
ks_dashboard_item_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item")
|
ks_dashboard_item_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M24 24C29.5228 24 34 19.5228 34 14C34 8.47715 29.5228 4 24 4C18.4772 4 14 8.47715 14 14C14 19.5228 18.4772 24 24 24Z"
|
||||||
|
stroke="" stroke-width="1.49595" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/>
|
||||||
|
<path d="M10 40C10 33.3726 16.3726 28 24 28C31.6274 28 38 33.3726 38 40"
|
||||||
|
stroke="" stroke-width="1.49595" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 521 B |
|
|
@ -401,7 +401,6 @@ export class Ksdashboardgraph extends Component{
|
||||||
// 3D Bar Chart Implementation
|
// 3D Bar Chart Implementation
|
||||||
create3DBarChart(chart, data, ks_data, item) {
|
create3DBarChart(chart, data, ks_data, item) {
|
||||||
// Create axes
|
// Create axes
|
||||||
debugger;
|
|
||||||
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
|
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
|
||||||
categoryAxis.dataFields.category = "category";
|
categoryAxis.dataFields.category = "category";
|
||||||
categoryAxis.renderer.labels.template.rotation = -45;
|
categoryAxis.renderer.labels.template.rotation = -45;
|
||||||
|
|
@ -736,7 +735,6 @@ export class Ksdashboardgraph extends Component{
|
||||||
['ks_bar_chart','ks_horizontalBar_chart','ks_pie_chart','ks_doughnut_chart'].includes(item.ks_dashboard_item_type);
|
['ks_bar_chart','ks_horizontalBar_chart','ks_pie_chart','ks_doughnut_chart'].includes(item.ks_dashboard_item_type);
|
||||||
|
|
||||||
if (use3D) {
|
if (use3D) {
|
||||||
debugger;
|
|
||||||
switch (theme) {
|
switch (theme) {
|
||||||
case "dark":
|
case "dark":
|
||||||
am4core.unuseAllThemes();
|
am4core.unuseAllThemes();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,218 @@
|
||||||
|
/** @odoo-module **/
|
||||||
|
import { Component, useState, useEffect, onWillUpdateProps, useRef, onMounted, onWillUnmount } from "@odoo/owl";
|
||||||
|
import { globalfunction } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||||
|
import { loadBundle } from "@web/core/assets";
|
||||||
|
import { useService } from "@web/core/utils/hooks";
|
||||||
|
import { _t } from "@web/core/l10n/translation";
|
||||||
|
import { onAudioEnded } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||||
|
import { rpc } from "@web/core/network/rpc";
|
||||||
|
|
||||||
|
export class Ksdashboardprofile extends Component {
|
||||||
|
setup() {
|
||||||
|
debugger;
|
||||||
|
var self = this;
|
||||||
|
this.orm = useService("orm");
|
||||||
|
this.actionService = useService("action");
|
||||||
|
this.ks_profile = useRef('ks_profile');
|
||||||
|
this.ks_container_class = 'grid-stack-item';
|
||||||
|
this.aiAudioRef = useRef("aiAudioRef");
|
||||||
|
this.ks_inner_container_class = 'grid-stack-item-content';
|
||||||
|
this.state = useState({
|
||||||
|
employee: {
|
||||||
|
name: '',
|
||||||
|
image_1920: '',
|
||||||
|
job_id: null,
|
||||||
|
current_company_exp: null,
|
||||||
|
doj: '',
|
||||||
|
employee_id: null,
|
||||||
|
birthday: '',
|
||||||
|
attendance_state: null,
|
||||||
|
mobile_phone: '',
|
||||||
|
work_email: '',
|
||||||
|
private_street: '',
|
||||||
|
department_id: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.storeService = useService("mail.store");
|
||||||
|
this.item = this.props.item;
|
||||||
|
this.ks_dashboard_data = this.props.dashboard_data;
|
||||||
|
this.ks_ai_analysis = this.ks_dashboard_data.ks_ai_explain_dash;
|
||||||
|
|
||||||
|
if (this.ks_ai_analysis) {
|
||||||
|
this.ks_container_class = 'grid-stack-item ks_ai_explain_tile';
|
||||||
|
this.ks_inner_container_class = 'grid-stack-item-content ks_ai_dashboard_item';
|
||||||
|
} else {
|
||||||
|
this.ks_container_class = 'grid-stack-item';
|
||||||
|
this.ks_inner_container_class = 'encapsulated-profile-tile grid-stack-item-content';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.item.ks_ai_analysis && this.item.ks_ai_analysis) {
|
||||||
|
var ks_analysis = this.item.ks_ai_analysis.split('ks_gap');
|
||||||
|
this.ks_ai_analysis_1 = ks_analysis[0];
|
||||||
|
this.ks_ai_analysis_2 = ks_analysis[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.prepare_profile();
|
||||||
|
var update_interval = this.props.dashboard_data.ks_set_interval;
|
||||||
|
|
||||||
|
onWillUpdateProps(async (nextprops) => {
|
||||||
|
if (nextprops.ksdatefilter != 'none') {
|
||||||
|
await this.ksFetchUpdateProfile(this.item.id, this.props.dashboard_data.context);
|
||||||
|
}
|
||||||
|
if (Object.keys(nextprops.pre_defined_filter).length) {
|
||||||
|
if (nextprops.pre_defined_filter?.item_ids?.includes(this.item.id)) {
|
||||||
|
await this.ksFetchUpdateProfile(this.item.id, this.props.dashboard_data.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Object.keys(nextprops.custom_filter).length) {
|
||||||
|
if (nextprops.custom_filter?.item_ids?.includes(this.item.id)) {
|
||||||
|
await this.ksFetchUpdateProfile(this.item.id, this.props.dashboard_data.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (update_interval && !this.env.inDialog) {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
this.ksFetchUpdateProfile(this.item.id, this.props.dashboard_data.context);
|
||||||
|
}, update_interval);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (this.ks_ai_analysis) {
|
||||||
|
const dashboardItems = this.ks_profile.el.querySelectorAll('.ks_dashboarditem_id');
|
||||||
|
dashboardItems.forEach(item => {
|
||||||
|
item.classList.add('ks_ai_chart_body');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.aiAudioRef.el?.addEventListener('ended', onAudioEnded);
|
||||||
|
});
|
||||||
|
|
||||||
|
onWillUnmount(() => {
|
||||||
|
this.aiAudioRef.el?.removeEventListener('ended', onAudioEnded);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ksFetchUpdateProfile(item_id, domain) {
|
||||||
|
var self = this;
|
||||||
|
if (!domain) {
|
||||||
|
if (this.__owl__.parent.component.hasOwnProperty('ksGetParamsForItemFetch') &&
|
||||||
|
this.__owl__.parent.component?.ksGetParamsForItemFetch(item_id) instanceof Function) {
|
||||||
|
domain = this.__owl__.parent.component?.ksGetParamsForItemFetch(item_id);
|
||||||
|
} else {
|
||||||
|
domain = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpc("/web/dataset/call_kw/", {
|
||||||
|
model: 'ks_dashboard_ninja.board',
|
||||||
|
method: 'ks_fetch_item',
|
||||||
|
args: [
|
||||||
|
[parseInt(item_id)], self.ks_dashboard_data.ks_dashboard_id, domain
|
||||||
|
],
|
||||||
|
kwargs: { context: this.props.dashboard_data.context },
|
||||||
|
}).then(function (new_item_data) {
|
||||||
|
this.ks_dashboard_data.ks_item_data[item_id] = new_item_data[item_id];
|
||||||
|
this.item = this.ks_dashboard_data.ks_item_data[item_id];
|
||||||
|
this.__owl__.parent.component.ks_dashboard_data.ks_item_data[this.item.id] = new_item_data[item_id];
|
||||||
|
this.prepare_profile();
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
ksStopClickPropagation(e) {
|
||||||
|
this.ksAllowItemClick = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_profile() {
|
||||||
|
var self = this;
|
||||||
|
var ks_rgba_background_color, ks_rgba_font_color, ks_rgba_button_color;
|
||||||
|
|
||||||
|
this.item.ksIsDashboardManager = self.ks_dashboard_data.ks_dashboard_manager;
|
||||||
|
this.item.ksIsUser = true;
|
||||||
|
this.ks_rgba_background_color = self._ks_get_rgba_format(this.item.ks_background_color);
|
||||||
|
this.ks_rgba_font_color = self._ks_get_rgba_format(this.item.ks_font_color);
|
||||||
|
this.ks_rgba_button_color = self._ks_get_rgba_format(this.item.ks_button_color);
|
||||||
|
|
||||||
|
if (this.item.ks_info) {
|
||||||
|
var ks_description = this.item.ks_info.split('\n');
|
||||||
|
var ks_description = ks_description.filter(element => element !== '');
|
||||||
|
} else {
|
||||||
|
var ks_description = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ks_info = ks_description;
|
||||||
|
this.ks_dashboard_list = self.ks_dashboard_data.ks_dashboard_list;
|
||||||
|
this.style_main_body = this._ksMainBodyStyle(this.ks_rgba_background_color, this.ks_rgba_font_color, this.item).background_style;
|
||||||
|
|
||||||
|
// Fetch employee data
|
||||||
|
this.fetchEmployeeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchEmployeeData() {
|
||||||
|
try {
|
||||||
|
debugger;
|
||||||
|
const employeeData = await this.orm.call("hr.employee", 'get_user_employee_details');
|
||||||
|
debugger;
|
||||||
|
if (employeeData && employeeData.length > 0) {
|
||||||
|
const employee = employeeData[0];
|
||||||
|
this.state.employee = {
|
||||||
|
name: employee.name,
|
||||||
|
image_1920: employee.image_1920,
|
||||||
|
doj: employee.doj,
|
||||||
|
job_id: employee.job_id,
|
||||||
|
employee_id: employee.employee_id,
|
||||||
|
current_company_exp: employee.current_company_exp,
|
||||||
|
attendance_state: employee.attendance_state,
|
||||||
|
birthday: employee.birthday,
|
||||||
|
mobile_phone: employee.mobile_phone,
|
||||||
|
work_email: employee.work_email,
|
||||||
|
private_street: employee.private_street,
|
||||||
|
department_id: employee.department_id ? employee.department_id[1] : ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching employee data:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async attendance_sign_in_out() {
|
||||||
|
try {
|
||||||
|
await this.orm.call('hr.employee', 'attendance_manual', [[this.state.employee.id]]);
|
||||||
|
this.state.employee.attendance_state =
|
||||||
|
this.state.employee.attendance_state === 'checked_in' ? 'checked_out' : 'checked_in';
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating attendance:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ks_get_rgba_format(val) {
|
||||||
|
var rgba = val.split(',')[0].match(/[A-Za-z0-9]{2}/g);
|
||||||
|
rgba = rgba.map(function (v) {
|
||||||
|
return parseInt(v, 16);
|
||||||
|
}).join(",");
|
||||||
|
return "rgba(" + rgba + "," + val.split(',')[1] + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
_ksMainBodyStyle(ks_rgba_background_color, ks_rgba_font_color, tile) {
|
||||||
|
var background_style = "background-color:" + ks_rgba_background_color + ";color : " + ks_rgba_font_color + ";";
|
||||||
|
return {
|
||||||
|
'background_style': background_style,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ksdashboardprofile.props = {
|
||||||
|
item: { type: Object, Optional: true },
|
||||||
|
dashboard_data: { type: Object, Optional: true },
|
||||||
|
ksdatefilter: { type: String, Optional: true },
|
||||||
|
pre_defined_filter: { type: Object, Optional: true },
|
||||||
|
custom_filter: { type: Object, Optional: true },
|
||||||
|
ks_speak: { type: Function, Optional: true },
|
||||||
|
hideButtons: { type: Number, optional: true },
|
||||||
|
on_dialog: { type: Boolean, optional: true },
|
||||||
|
generate_dialog: { type: Boolean, optional: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
Ksdashboardprofile.template = "Ksdashboardprofile";
|
||||||
|
|
@ -0,0 +1,330 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
<t t-name="Ksdashboardprofile">
|
||||||
|
<t t-if="props.on_dialog">
|
||||||
|
<div class="explain-ai pt-3">
|
||||||
|
<div class="container">
|
||||||
|
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_profile">
|
||||||
|
<div class="row ks_ai_explain_body">
|
||||||
|
<t t-if="ks_ai_analysis">
|
||||||
|
<div class="col-xl-6 col-12">
|
||||||
|
<div class="charts-sec ks_explain_ai">
|
||||||
|
<t t-call="ks_profile_layout"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xl-6 col-12">
|
||||||
|
<div class="charts-data h-100">
|
||||||
|
<!-- <div class="charts-content-box">-->
|
||||||
|
<!-- <t t-call="ks_item_explanation"/>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||||
|
<div class="voice-cricle">
|
||||||
|
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||||
|
class="img-fluid"/>
|
||||||
|
</div>
|
||||||
|
<div class="comp-gif d-none">
|
||||||
|
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||||
|
class="img-fluid"/>
|
||||||
|
</div>
|
||||||
|
<audio t-ref="aiAudioRef"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<t t-call="ks_profile_layout"/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<div t-att-class="'ks_item_click ' + ks_container_class" t-att-id="item.id" t-ref="ks_profile">
|
||||||
|
<t t-if="ks_ai_analysis">
|
||||||
|
<div class="ks_ai_explain_body">
|
||||||
|
<t t-call="ks_profile_layout"/>
|
||||||
|
<!-- <t t-call="ks_item_explanation"/>-->
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<t t-call="ks_profile_layout"/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<t t-name="ks_profile_layout">
|
||||||
|
<div t-att-class="'ks_dashboarditem_id ks_profile_carousel encapsulated-profile-container ks_explain_ai_view ks_dashboard_profile ks_dashboard_item_hover ' + ks_inner_container_class"
|
||||||
|
t-att-style="style_main_body"
|
||||||
|
t-att-title="item.ks_info" t-att-id="item.id">
|
||||||
|
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header ks_dashboard_item_header_hover"
|
||||||
|
t-att-data-item_id="item.id">
|
||||||
|
<t t-if="item.ksIsDashboardManager and props.hideButtons and !props.on_dialog">
|
||||||
|
<button title="Move/Duplicate" data-bs-toggle="dropdown"
|
||||||
|
class="ks_dashboard_item_action dropdown-toggle img-bg hover-item me-lg-2 kpi-tile-img bg-white d-md-block d-none"
|
||||||
|
type="button"
|
||||||
|
t-att-style="'color:'+ ks_rgba_button_color + ';'"
|
||||||
|
aria-expanded="true">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.59351 3.92004H3.40682C2.26682 3.92004 1.3335 4.85337 1.3335 5.99337V13.5667C1.3335 14.5334 2.02683 14.9467 2.87349 14.4734L5.49349 13.0134C5.77349 12.86 6.22683 12.86 6.50016 13.0134L9.12016 14.4734C9.96682 14.9467 10.6602 14.5334 10.6602 13.5667V5.99337C10.6668 4.85337 9.73351 3.92004 8.59351 3.92004Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.6668 5.99337V13.5667C10.6668 14.5334 9.9735 14.94 9.12683 14.4734L6.50684 13.0134C6.22684 12.86 5.77349 12.86 5.49349 13.0134L2.87349 14.4734C2.02683 14.94 1.3335 14.5334 1.3335 13.5667V5.99337C1.3335 4.85337 2.26682 3.92004 3.40682 3.92004H8.59351C9.73351 3.92004 10.6668 4.85337 10.6668 5.99337Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M14.6668 3.4067V10.98C14.6668 11.9467 13.9735 12.3534 13.1268 11.8867L10.6668 10.5134V5.99337C10.6668 4.85337 9.73351 3.92004 8.59351 3.92004H5.3335V3.4067C5.3335 2.2667 6.26682 1.33337 7.40682 1.33337H12.5935C13.7335 1.33337 14.6668 2.2667 14.6668 3.4067Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<ul role="menu" class="ks_dashboard_menu_container form-input-box form-control encapsulated-form-arrow dropdown-menu dropdown-menu-right">
|
||||||
|
<li class="ks_md_heading m-2">
|
||||||
|
<span>Select Dashboard</span>
|
||||||
|
</li>
|
||||||
|
<li class="m-2">
|
||||||
|
<select class="o_input o_group_selector o_add_group ks_dashboard_select">
|
||||||
|
<t t-foreach="ks_dashboard_list" t-as="ks_dashboard" t-key="ks_dashboard.id">
|
||||||
|
<option t-att-value="ks_dashboard['id']">
|
||||||
|
<t t-esc="ks_dashboard['name']"/>
|
||||||
|
</option>
|
||||||
|
</t>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
<li class="m-2">
|
||||||
|
<button class="dash-btn-red o_apply_group o_add_group ks_duplicate_item"
|
||||||
|
tabindex="-1" type="button">Duplicate
|
||||||
|
</button>
|
||||||
|
<button class="dash-btn-red o_apply_group o_add_group ks_move_item" tabindex="-1"
|
||||||
|
type="button">Move
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button title="Quick Customize"
|
||||||
|
class="ks_dashboard_quick_edit_action_popup d-md-block d-none img-bg hover-item me-lg-2 kpi-tile-img bg-white"
|
||||||
|
t-att-style="'color:'+ ks_rgba_button_color + ';'"
|
||||||
|
type="button" t-att-data-item-id="item.id">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M9.16675 1.66663H7.50008C3.33341 1.66663 1.66675 3.33329 1.66675 7.49996V12.5C1.66675 16.6666 3.33341 18.3333 7.50008 18.3333H12.5001C16.6667 18.3333 18.3334 16.6666 18.3334 12.5V10.8333" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||||
|
<path d="M13.3666 2.51663L6.7999 9.0833C6.5499 9.3333 6.2999 9.82497 6.2499 10.1833L5.89157 12.6916C5.75823 13.6 6.3999 14.2333 7.30823 14.1083L9.81657 13.75C10.1666 13.7 10.6582 13.45 10.9166 13.2L17.4832 6.6333C18.6166 5.49997 19.1499 4.1833 17.4832 2.51663C15.8166 0.849966 14.4999 1.3833 13.3666 2.51663Z" stroke="currentColor" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||||
|
<path d="M12.425 3.45837C12.9834 5.45004 14.5417 7.00837 16.5417 7.57504" stroke="currentColor" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="ks_chart_inner_buttons dropdown d-md-none dn-setting-panel">
|
||||||
|
<button data-bs-toggle="dropdown"
|
||||||
|
class="ks_dashboard_item_action bg-transparent img-bg hover-item me-lg-2 kpi-tile-img dropdown-toggle"
|
||||||
|
type="button"
|
||||||
|
t-att-style="'color:'+ ks_rgba_button_color + ';'"
|
||||||
|
aria-expanded="true">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z" fill="#4B5563" stroke="currentColor" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M1.33301 8.58667V7.41333C1.33301 6.72 1.89967 6.14667 2.59967 6.14667C3.80634 6.14667 4.29967 5.29333 3.69301 4.24667C3.34634 3.64667 3.55301 2.86667 4.15967 2.52L5.31301 1.86C5.83967 1.54666 6.51967 1.73333 6.83301 2.26L6.90634 2.38666C7.50634 3.43333 8.49301 3.43333 9.09967 2.38666L9.17301 2.26C9.48634 1.73333 10.1663 1.54666 10.693 1.86L11.8463 2.52C12.453 2.86667 12.6597 3.64667 12.313 4.24667C11.7063 5.29333 12.1997 6.14667 13.4063 6.14667C14.0997 6.14667 14.673 6.71333 14.673 7.41333V8.58667C14.673 9.28 14.1063 9.85333 13.4063 9.85333C12.1997 9.85333 11.7063 10.7067 12.313 11.7533C12.6597 12.36 12.453 13.1333 11.8463 13.48L10.693 14.14C10.1663 14.4533 9.48634 14.2667 9.17301 13.74L9.09967 13.6133C8.49967 12.5667 7.51301 12.5667 6.90634 13.6133L6.83301 13.74C6.51967 14.2667 5.83967 14.4533 5.31301 14.14L4.15967 13.48C3.55301 13.1333 3.34634 12.3533 3.69301 11.7533C4.29967 10.7067 3.80634 9.85333 2.59967 9.85333C1.89967 9.85333 1.33301 9.28 1.33301 8.58667Z" stroke="currentColor" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div role="menu" class="dropdown-menu dropdown-menu-right ks_chart_inner_min_width">
|
||||||
|
<div class="ks_chart_export_menu">
|
||||||
|
<div class="ks_dashboard_item_customize ks_chart_export_menu_item"
|
||||||
|
t-att-data-item_id="item.id"
|
||||||
|
data-format="chart_xls">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.16675 1.66663H7.50008C3.33341 1.66663 1.66675 3.33329 1.66675 7.49996V12.5C1.66675 16.6666 3.33341 18.3333 7.50008 18.3333H12.5001C16.6667 18.3333 18.3334 16.6666 18.3334 12.5V10.8333" stroke="#241C1D" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M13.3666 2.51663L6.7999 9.0833C6.5499 9.3333 6.2999 9.82497 6.2499 10.1833L5.89157 12.6916C5.75823 13.6 6.3999 14.2333 7.30823 14.1083L9.81657 13.75C10.1666 13.7 10.6582 13.45 10.9166 13.2L17.4832 6.6333C18.6166 5.49997 19.1499 4.1833 17.4832 2.51663C15.8166 0.849966 14.4999 1.3833 13.3666 2.51663Z" stroke="#241C1D" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12.425 3.45837C12.9834 5.45004 14.5417 7.00837 16.5417 7.57504" stroke="#241C1D" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
<span>Customize Item</span>
|
||||||
|
</div>
|
||||||
|
<div class="ks_dashboard_item_delete ks_chart_export_menu_item"
|
||||||
|
t-att-data-item_id="item.id"
|
||||||
|
data-format="chart_xls">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="" class="me-1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" fill="#241C1D"/>
|
||||||
|
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5.66699 3.31337L5.81366 2.44004C5.92033 1.80671 6.00033 1.33337 7.12699 1.33337H8.87366C10.0003 1.33337 10.087 1.83337 10.187 2.44671L10.3337 3.31337" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12.5669 6.09338L12.1336 12.8067C12.0603 13.8534 12.0003 14.6667 10.1403 14.6667H5.86026C4.00026 14.6667 3.94026 13.8534 3.86693 12.8067L3.43359 6.09338" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6.88672 11H9.10672" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6.33301 8.33337H9.66634" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg> <span>Remove Item</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-if="item.ksIsUser and props.hideButtons and !props.on_dialog">
|
||||||
|
<div class="ks_chart_inner_buttons dropdown">
|
||||||
|
<button title="Info" data-bs-toggle="dropdown"
|
||||||
|
class="ks_item_description dropdown-toggle o-no-caret img-bg hover-item me-lg-2 kpi-tile-img bg-white d-md-block d-none"
|
||||||
|
type="button"
|
||||||
|
t-att-style="'color:'+ ks_rgba_button_color + ';'"
|
||||||
|
aria-expanded="true">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.00004 14.6667C11.6667 14.6667 14.6667 11.6667 14.6667 8.00004C14.6667 4.33337 11.6667 1.33337 8.00004 1.33337C4.33337 1.33337 1.33337 4.33337 1.33337 8.00004C1.33337 11.6667 4.33337 14.6667 8.00004 14.6667Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8 5.33337V8.66671" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.99646 10.6666H8.00245" stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div role="menu" class="dropdown-menu dropdown-menu-right" style="width:20rem">
|
||||||
|
<div class="ks_chart_export_menu">
|
||||||
|
<div class="ks_chart_export_menu_header" style="margin-left:-10px">
|
||||||
|
<span>Info</span>
|
||||||
|
</div>
|
||||||
|
<div class="ks_info" style="margin-left:10px">
|
||||||
|
<span>Company: <t t-esc="item.ks_company"/></span>
|
||||||
|
</div>
|
||||||
|
<div class="ks_info" style="margin-left:10px">
|
||||||
|
<t t-if="ks_info">
|
||||||
|
<t t-foreach="ks_info" t-as="ks_description" t-key="ks_description_index">
|
||||||
|
<span><t t-esc="ks_description"/></span>
|
||||||
|
<br></br>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-if="item.ksIsUser and props.hideButtons and !props.on_dialog">
|
||||||
|
<div class="ks_chart_inner_buttons d-md-block d-none">
|
||||||
|
<button title="More" data-bs-toggle="dropdown"
|
||||||
|
class="ks_dashboard_item_action img-bg hover-item me-lg-2 kpi-tile-img bg-white dropdown-toggle o-no-caret"
|
||||||
|
type="button"
|
||||||
|
t-att-style="'color:'+ ks_rgba_button_color + ';'"
|
||||||
|
aria-expanded="true">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.2916 15.8333C12.2916 17.1 11.2666 18.125 9.99992 18.125C8.73325 18.125 7.70825 17.1 7.70825 15.8333C7.70825 14.5667 8.73325 13.5417 9.99992 13.5417C11.2666 13.5417 12.2916 14.5667 12.2916 15.8333ZM8.95825 15.8333C8.95825 16.4083 9.42492 16.875 9.99992 16.875C10.5749 16.875 11.0416 16.4083 11.0416 15.8333C11.0416 15.2583 10.5749 14.7917 9.99992 14.7917C9.42492 14.7917 8.95825 15.2583 8.95825 15.8333Z" fill="currentColor"/>
|
||||||
|
<path d="M12.2916 4.16671C12.2916 5.43337 11.2666 6.45837 9.99992 6.45837C8.73325 6.45837 7.70825 5.43337 7.70825 4.16671C7.70825 2.90004 8.73325 1.87504 9.99992 1.87504C11.2666 1.87504 12.2916 2.90004 12.2916 4.16671ZM8.95825 4.16671C8.95825 4.74171 9.42492 5.20837 9.99992 5.20837C10.5749 5.20837 11.0416 4.74171 11.0416 4.16671C11.0416 3.59171 10.5749 3.12504 9.99992 3.12504C9.42492 3.12504 8.95825 3.59171 8.95825 4.16671Z" fill="currentColor"/>
|
||||||
|
<path d="M12.2916 9.99996C12.2916 11.2666 11.2666 12.2916 9.99992 12.2916C8.73325 12.2916 7.70825 11.2666 7.70825 9.99996C7.70825 8.73329 8.73325 7.70829 9.99992 7.70829C11.2666 7.70829 12.2916 8.73329 12.2916 9.99996ZM8.95825 9.99996C8.95825 10.575 9.42492 11.0416 9.99992 11.0416C10.5749 11.0416 11.0416 10.575 11.0416 9.99996C11.0416 9.42496 10.5749 8.95829 9.99992 8.95829C9.42492 8.95829 8.95825 9.42496 8.95825 9.99996Z" fill="currentColor"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div role="menu" class="dropdown-menu dropdown-menu-right">
|
||||||
|
<div class="ks_chart_export_menu">
|
||||||
|
<div class="ks_chart_json_export ks_chart_export_menu_item d-flex"
|
||||||
|
t-att-data-item_id="item_id"
|
||||||
|
data-format="chart_xls">
|
||||||
|
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/document-upload.svg" alt="document-upload" class="img-fluid" loading="lazy"/>
|
||||||
|
<span>Export Item</span>
|
||||||
|
</div>
|
||||||
|
<t t-if="item.ksIsDashboardManager and props.hideButtons and !props.on_dialog">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<button type="button" title="Remove Item"
|
||||||
|
class="ks_dashboard_item_delete d-md-flex d-none img-bg hover-item me-lg-2 kpi-tile-img bg-white"
|
||||||
|
t-att-style="'color:'+ ks_rgba_button_color + ';'">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" class="me-1" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" fill="#4B5563"/>
|
||||||
|
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5.66699 3.31337L5.81366 2.44004C5.92033 1.80671 6.00033 1.33337 7.12699 1.33337H8.87366C10.0003 1.33337 10.087 1.83337 10.187 2.44671L10.3337 3.31337" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12.5669 6.09338L12.1336 12.8067C12.0603 13.8534 12.0003 14.6667 10.1403 14.6667H5.86026C4.00026 14.6667 3.94026 13.8534 3.86693 12.8067L3.43359 6.09338" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6.88672 11H9.10672" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6.33301 8.33337H9.66634" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<button id='ks_ai_item_exp_dash' class="img-bg hover-item me-lg-2 kpi-tile-img bg-white"
|
||||||
|
t-on-click="_onButtonClick4" title="AI provides the insights of the item">
|
||||||
|
<img src="/ks_dashboard_ninja/static/images/favorite-chart.svg" alt="create" class="img-fluid" loading="lazy"/>
|
||||||
|
Explain With AI
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<button class="ks_dashboard_item_chatter_wizard img-bg hover-item me-lg-2 kpi-tile-img bg-white" title="Internal Chat" type="button" t-on-click="_openChatWizard">
|
||||||
|
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/messages.svg" alt="messages" class="img-fluid" loading="lazy"/>
|
||||||
|
Chat
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Profile Card Content -->
|
||||||
|
<div class="ks-profile-header">
|
||||||
|
<div class="ks-profile-image">
|
||||||
|
<img t-att-src="'data:image/png;base64,' + state.employee.image_1920"
|
||||||
|
alt="Employee Image"
|
||||||
|
t-att-class="state.employee.image_1920 ? '' : 'ks-default-image'" />
|
||||||
|
</div>
|
||||||
|
<div class="ks-profile-details">
|
||||||
|
<div class="ks-profile-info">
|
||||||
|
<h1>
|
||||||
|
<t t-esc="state.employee.name"/>
|
||||||
|
<t t-if="state.employee.employee_id">
|
||||||
|
- <t t-esc="state.employee.employee_id"/>
|
||||||
|
</t>
|
||||||
|
</h1>
|
||||||
|
<p class="ks-job-title">
|
||||||
|
<t t-if="state.employee.job_id">
|
||||||
|
<t t-esc="state.employee.job_id[1]"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.job_id">
|
||||||
|
Add Job Title
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<p class="ks-joined">
|
||||||
|
<t t-if="state.employee.doj">
|
||||||
|
Joined <t t-esc="state.employee.current_company_exp"/> ago
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.doj">
|
||||||
|
Joined Date: <t t-esc="state.employee.doj"/>
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Birthday :
|
||||||
|
<t t-if="state.employee.birthday">
|
||||||
|
<t t-esc="state.employee.birthday"/>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
--/--/----
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="ks-profile-contact">
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-phone"></i>
|
||||||
|
<t t-if="state.employee.mobile_phone">
|
||||||
|
<t t-esc="state.employee.mobile_phone"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.mobile_phone">
|
||||||
|
---
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-envelope"></i>
|
||||||
|
<t t-if="state.employee.work_email">
|
||||||
|
<t t-esc="state.employee.work_email"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.work_email">
|
||||||
|
---
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-home"></i> Address:
|
||||||
|
<t t-if="state.employee.private_street">
|
||||||
|
<t t-esc="state.employee.private_street"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.private_street">
|
||||||
|
---
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ks-stat-att" t-on-click="attendance_sign_in_out">
|
||||||
|
<t t-if="state.employee.attendance_state == 'checked_out'">
|
||||||
|
<div class="ks-stat-atticon">
|
||||||
|
<i class="fa fa-sign-in"></i>
|
||||||
|
</div>
|
||||||
|
<div class="ks-stat-attcontent">
|
||||||
|
<p>Check In</p>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-if="state.employee.attendance_state == 'checked_in'">
|
||||||
|
<div class="ks-stat-atticon">
|
||||||
|
<i class="fa fa-sign-out"></i>
|
||||||
|
</div>
|
||||||
|
<div class="ks-stat-attcontent">
|
||||||
|
<p>Check Out</p>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
|
||||||
|
</templates>
|
||||||
|
|
@ -0,0 +1,239 @@
|
||||||
|
.ks-profile-container {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #2575fc);
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-header {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-image {
|
||||||
|
flex: 0 0 150px;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 20px;
|
||||||
|
border: 4px solid rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-default-image {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-details {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-info h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.8em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-job-title {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 1.1em;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-joined {
|
||||||
|
font-size: 0.9em;
|
||||||
|
opacity: 0.9;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-contact {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-contact p {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-contact i {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-stat-att {
|
||||||
|
width: 100px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-stat-att:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-stat-atticon {
|
||||||
|
font-size: 2em;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-stat-attcontent p {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #fff;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ks-profile-container {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #2575fc);
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-header {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-image {
|
||||||
|
flex: 0 0 150px;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 20px;
|
||||||
|
border: 4px solid rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-default-image {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-details {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-info h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.8em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-job-title {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 1.1em;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-joined {
|
||||||
|
font-size: 0.9em;
|
||||||
|
opacity: 0.9;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-contact {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-contact p {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-profile-contact i {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-stat-att {
|
||||||
|
width: 100px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-stat-att:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-stat-atticon {
|
||||||
|
font-size: 2em;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-stat-attcontent p {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #fff;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Additional styles for the dashboard container */
|
||||||
|
.encapsulated-profile-container {
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #2575fc);
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -7,6 +7,8 @@ import { Ksdashboardtile } from '@ks_dashboard_ninja/components/ks_dashboard_til
|
||||||
import { patch } from "@web/core/utils/patch";
|
import { patch } from "@web/core/utils/patch";
|
||||||
import { rpc } from "@web/core/network/rpc";
|
import { rpc } from "@web/core/network/rpc";
|
||||||
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
||||||
|
import { Ksdashboardprofile } from '@ks_dashboard_ninja/components/ks_dashboard_profile_view/ks_dashboard_profile';
|
||||||
|
|
||||||
|
|
||||||
patch(Ksdashboardgraph.prototype,{
|
patch(Ksdashboardgraph.prototype,{
|
||||||
|
|
||||||
|
|
@ -35,6 +37,7 @@ patch(Ksdashboardgraph.prototype,{
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
patch(Ksdashboardkpiview.prototype,{
|
patch(Ksdashboardkpiview.prototype,{
|
||||||
|
|
||||||
async _openChatWizard(ev){
|
async _openChatWizard(ev){
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import { Ksdashboardtile } from '@ks_dashboard_ninja/components/ks_dashboard_til
|
||||||
import { Ksdashboardtodo } from '@ks_dashboard_ninja/components/ks_dashboard_to_do_item/ks_dashboard_to_do';
|
import { Ksdashboardtodo } from '@ks_dashboard_ninja/components/ks_dashboard_to_do_item/ks_dashboard_to_do';
|
||||||
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
||||||
import { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs';
|
import { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs';
|
||||||
|
import { Ksdashboardprofile } from '@ks_dashboard_ninja/components/ks_dashboard_profile_view/ks_dashboard_profile';
|
||||||
import { Dialog } from "@web/core/dialog/dialog";
|
import { Dialog } from "@web/core/dialog/dialog";
|
||||||
import { rpc } from "@web/core/network/rpc";
|
import { rpc } from "@web/core/network/rpc";
|
||||||
|
|
||||||
|
|
@ -208,7 +209,7 @@ export class KsAIDashboardNinja extends Component {
|
||||||
|
|
||||||
// Add widgets to the grid
|
// Add widgets to the grid
|
||||||
this.state.ks_dashboard_items.forEach(function (item) {
|
this.state.ks_dashboard_items.forEach(function (item) {
|
||||||
var graphs = ['ks_scatter_chart', 'ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_doughnut_chart', 'ks_polarArea_chart', 'ks_pie_chart', 'ks_flower_view', 'ks_radar_view', 'ks_radialBar_chart', 'ks_map_view', 'ks_funnel_chart', 'ks_bullet_chart', 'ks_to_do', 'ks_list_view'];
|
var graphs = ['ks_scatter_chart', 'ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_doughnut_chart', 'ks_polarArea_chart', 'ks_pie_chart', 'ks_flower_view', 'ks_radar_view', 'ks_radialBar_chart', 'ks_map_view', 'ks_funnel_chart', 'ks_bullet_chart', 'ks_to_do', 'ks_list_view', 'ks_profile'];
|
||||||
var ksPreview = document.getElementById(item.id);
|
var ksPreview = document.getElementById(item.id);
|
||||||
|
|
||||||
if (ksPreview) {
|
if (ksPreview) {
|
||||||
|
|
@ -533,6 +534,6 @@ export class KsAIDashboardNinja extends Component {
|
||||||
speak_once(ev,item){
|
speak_once(ev,item){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KsAIDashboardNinja.components = { Ksdashboardtile,Ksdashboardgraph,Ksdashboardkpiview, Ksdashboardtodo, Dialog, FormViewDialog};
|
KsAIDashboardNinja.components = { Ksdashboardtile,Ksdashboardgraph,Ksdashboardkpiview, Ksdashboardprofile, Ksdashboardtodo, Dialog, FormViewDialog};
|
||||||
KsAIDashboardNinja.template = "ksaiDashboardNinjaHeader"
|
KsAIDashboardNinja.template = "ksaiDashboardNinjaHeader"
|
||||||
registry.category("actions").add("ks_ai_dashboard_ninja",KsAIDashboardNinja);
|
registry.category("actions").add("ks_ai_dashboard_ninja",KsAIDashboardNinja);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ import { Ksdashboardgraph } from './../components/ks_dashboard_graphs/ks_dashboa
|
||||||
import { Ksdashboardtile } from './../components/ks_dashboard_tile_view/ks_dashboard_tile';
|
import { Ksdashboardtile } from './../components/ks_dashboard_tile_view/ks_dashboard_tile';
|
||||||
import { Ksdashboardtodo } from './../components/ks_dashboard_to_do_item/ks_dashboard_to_do';
|
import { Ksdashboardtodo } from './../components/ks_dashboard_to_do_item/ks_dashboard_to_do';
|
||||||
import { Ksdashboardkpiview } from './../components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
import { Ksdashboardkpiview } from './../components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
||||||
|
import { Ksdashboardprofile } from './../components/ks_dashboard_profile_view/ks_dashboard_profile';
|
||||||
|
|
||||||
|
|
||||||
import { rpc } from "@web/core/network/rpc";
|
import { rpc } from "@web/core/network/rpc";
|
||||||
import { user } from "@web/core/user";
|
import { user } from "@web/core/user";
|
||||||
|
|
||||||
|
|
@ -129,7 +132,7 @@ CustomDialog.props = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CustomDialog.components = { Dialog, Ksdashboardgraph, Ksdashboardtile, Ksdashboardkpiview, Ksdashboardtodo };
|
CustomDialog.components = { Dialog, Ksdashboardgraph, Ksdashboardtile, Ksdashboardkpiview, Ksdashboardtodo, Ksdashboardprofile };
|
||||||
|
|
||||||
CustomDialog.template = "ks_dashboard_ninja.CustomDialog";
|
CustomDialog.template = "ks_dashboard_ninja.CustomDialog";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import { Ksdashboardlistview } from '@ks_dashboard_ninja/components/ks_dashboard
|
||||||
import { Ksdashboardtodo } from '@ks_dashboard_ninja/components/ks_dashboard_to_do_item/ks_dashboard_to_do';
|
import { Ksdashboardtodo } from '@ks_dashboard_ninja/components/ks_dashboard_to_do_item/ks_dashboard_to_do';
|
||||||
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
||||||
import { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs';
|
import { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs';
|
||||||
|
import { Ksdashboardprofile } from '@ks_dashboard_ninja/components/ks_dashboard_profile_view/ks_dashboard_profile';
|
||||||
import { KschatwithAI } from '@ks_dashboard_ninja/components/chatwithAI/ks_chat';
|
import { KschatwithAI } from '@ks_dashboard_ninja/components/chatwithAI/ks_chat';
|
||||||
import { CustomFilter } from '@ks_dashboard_ninja/js/custom_filter';
|
import { CustomFilter } from '@ks_dashboard_ninja/js/custom_filter';
|
||||||
import { DateTimePicker } from "@web/core/datetime/datetime_picker";
|
import { DateTimePicker } from "@web/core/datetime/datetime_picker";
|
||||||
|
|
@ -379,7 +380,7 @@ export class KsDashboardNinja extends Component {
|
||||||
this.gridstackConfig = JSON.parse(this.ks_dashboard_data.ks_gridstack_config);
|
this.gridstackConfig = JSON.parse(this.ks_dashboard_data.ks_gridstack_config);
|
||||||
}
|
}
|
||||||
for (var i = 0; i < item.length; i++) {
|
for (var i = 0; i < item.length; i++) {
|
||||||
var graphs = ['ks_scatter_chart','ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_doughnut_chart','ks_polarArea_chart','ks_pie_chart','ks_flower_view', 'ks_radar_view','ks_radialBar_chart','ks_map_view','ks_funnel_chart','ks_bullet_chart', 'ks_to_do', 'ks_list_view']
|
var graphs = ['ks_scatter_chart','ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_doughnut_chart','ks_polarArea_chart','ks_pie_chart','ks_flower_view', 'ks_radar_view','ks_radialBar_chart','ks_map_view','ks_funnel_chart','ks_bullet_chart', 'ks_to_do', 'ks_list_view', 'ks_profile']
|
||||||
var ks_preview = document.getElementById(item[i].id)
|
var ks_preview = document.getElementById(item[i].id)
|
||||||
if (ks_preview && !this.ks_dashboard_data.ks_ai_explain_dash) {
|
if (ks_preview && !this.ks_dashboard_data.ks_ai_explain_dash) {
|
||||||
if (item[i].id in self.gridstackConfig) {
|
if (item[i].id in self.gridstackConfig) {
|
||||||
|
|
@ -2022,7 +2023,7 @@ export class KsDashboardNinja extends Component {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KsDashboardNinja.components = { Ksdashboardtile, Ksdashboardlistview, Ksdashboardgraph, Ksdashboardkpiview, Ksdashboardtodo, DateTimePicker, DateTimeInput,KschatwithAI, CustomFilter};
|
KsDashboardNinja.components = { Ksdashboardtile, Ksdashboardlistview, Ksdashboardgraph, Ksdashboardkpiview, Ksdashboardtodo, Ksdashboardprofile, DateTimePicker, DateTimeInput,KschatwithAI, CustomFilter};
|
||||||
KsDashboardNinja.template = "ks_dashboard_ninja.KsDashboardNinjaHeader"
|
KsDashboardNinja.template = "ks_dashboard_ninja.KsDashboardNinjaHeader"
|
||||||
registry.category("actions").add("ks_dashboard_ninja", KsDashboardNinja);
|
registry.category("actions").add("ks_dashboard_ninja", KsDashboardNinja);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export class KsGraphPreview extends Component {
|
||||||
el.remove();
|
el.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (rec.ks_dashboard_item_type !== 'ks_tile' && rec.ks_dashboard_item_type !== 'ks_kpi' &&
|
if (rec.ks_dashboard_item_type !== 'ks_tile' && rec.ks_dashboard_item_type !== 'ks_kpi' && rec.ks_dashboard_item_type !== 'ks_profile' &&
|
||||||
rec.ks_dashboard_item_type !== 'ks_list_view' && rec.ks_dashboard_item_type !== 'ks_to_do') {
|
rec.ks_dashboard_item_type !== 'ks_list_view' && rec.ks_dashboard_item_type !== 'ks_to_do') {
|
||||||
|
|
||||||
if (rec.ks_data_calculation_type !== "query") {
|
if (rec.ks_data_calculation_type !== "query") {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ export class KsDashboarditemtype extends Component {
|
||||||
{'id':14,'name':'List','Tech_name':'ks_list_view'},
|
{'id':14,'name':'List','Tech_name':'ks_list_view'},
|
||||||
{'id':15,'name':'Map','Tech_name':'ks_map_view'},
|
{'id':15,'name':'Map','Tech_name':'ks_map_view'},
|
||||||
{'id':16,'name':'To-do','Tech_name':'ks_to_do'},
|
{'id':16,'name':'To-do','Tech_name':'ks_to_do'},
|
||||||
{'id':17,'name':'KPI','Tech_name':'ks_kpi'}
|
{'id':17,'name':'KPI','Tech_name':'ks_kpi'},
|
||||||
|
{'id':18,'name':'Profile','Tech_name':'ks_profile'}
|
||||||
]});
|
]});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,15 @@
|
||||||
<path d="M14.7006 21.5609L20.8749 16.4059C21.3649 15.9943 22.0117 16.1119 22.3449 16.6607L24.6971 20.5809C25.0303 21.1297 25.6771 21.2277 26.1671 20.8357L32.3414 15.6807" stroke="" stroke-width="1.49595" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M14.7006 21.5609L20.8749 16.4059C21.3649 15.9943 22.0117 16.1119 22.3449 16.6607L24.6971 20.5809C25.0303 21.1297 25.6771 21.2277 26.1671 20.8357L32.3414 15.6807" stroke="" stroke-width="1.49595" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
|
<t t-elif="item_name === 'Profile'">
|
||||||
|
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M24 24C29.5228 24 34 19.5228 34 14C34 8.47715 29.5228 4 24 4C18.4772 4 14 8.47715 14 14C14 19.5228 18.4772 24 24 24Z"
|
||||||
|
stroke="" stroke-width="1.49595" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/>
|
||||||
|
<path d="M10 40C10 33.3726 16.3726 28 24 28C31.6274 28 38 33.3726 38 40"
|
||||||
|
stroke="" stroke-width="1.49595" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/>
|
||||||
|
</svg>
|
||||||
|
</t>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
/** @odoo-module */
|
||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
import { useState, onMounted } from "@odoo/owl";
|
||||||
|
import { useService } from "@web/core/utils/hooks";
|
||||||
|
import { Component } from "@odoo/owl";
|
||||||
|
|
||||||
|
class KsProfile extends Component {
|
||||||
|
setup() {
|
||||||
|
this.orm = useService("orm");
|
||||||
|
this.state = useState({
|
||||||
|
employee: {
|
||||||
|
name: '',
|
||||||
|
image_1920: '',
|
||||||
|
job_id: null,
|
||||||
|
current_company_exp: null,
|
||||||
|
doj: '',
|
||||||
|
employee_id: null,
|
||||||
|
birthday: '',
|
||||||
|
attendance_state: null,
|
||||||
|
mobile_phone: '',
|
||||||
|
work_email: '',
|
||||||
|
private_street: '',
|
||||||
|
department_id: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await this.fetchEmployeeData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchEmployeeData() {
|
||||||
|
try {
|
||||||
|
debugger;
|
||||||
|
const employeeData = await this.orm.call("hr.employee", 'get_user_employee_details');
|
||||||
|
if (employeeData && employeeData.length > 0) {
|
||||||
|
const employee = employeeData[0];
|
||||||
|
this.state.employee = {
|
||||||
|
name: employee.name,
|
||||||
|
image_1920: employee.image_1920,
|
||||||
|
doj: employee.doj,
|
||||||
|
job_id: employee.job_id,
|
||||||
|
employee_id: employee.employee_id,
|
||||||
|
current_company_exp: employee.current_company_exp,
|
||||||
|
attendance_state: employee.attendance_state,
|
||||||
|
birthday: employee.birthday,
|
||||||
|
mobile_phone: employee.mobile_phone,
|
||||||
|
work_email: employee.work_email,
|
||||||
|
private_street: employee.private_street,
|
||||||
|
department_id: employee.department_id ? employee.department_id[1] : ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching employee data:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async attendance_sign_in_out() {
|
||||||
|
try {
|
||||||
|
await this.orm.call('hr.employee', 'attendance_manual', [[this.state.employee.id]]);
|
||||||
|
this.state.employee.attendance_state =
|
||||||
|
this.state.employee.attendance_state === 'checked_in' ? 'checked_out' : 'checked_in';
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating attendance:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KsProfile.template = "ks_profile";
|
||||||
|
export const KsProfileField = {
|
||||||
|
component: KsProfile,
|
||||||
|
};
|
||||||
|
registry.category("fields").add('ks_profile_preview', KsProfileField);
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
<t t-name="ks_profile" owl="1">
|
||||||
|
<div class="ks-profile-container">
|
||||||
|
<div class="ks-profile-header">
|
||||||
|
<div class="ks-profile-image">
|
||||||
|
<img t-att-src="'data:image/png;base64,' + state.employee.image_1920"
|
||||||
|
alt="Employee Image"
|
||||||
|
t-att-class="state.employee.image_1920 ? '' : 'ks-default-image'" />
|
||||||
|
</div>
|
||||||
|
<div class="ks-profile-details">
|
||||||
|
<div class="ks-profile-info">
|
||||||
|
<h1>
|
||||||
|
<t t-esc="state.employee.name"/>
|
||||||
|
<t t-if="state.employee.employee_id">
|
||||||
|
- <t t-esc="state.employee.employee_id"/>
|
||||||
|
</t>
|
||||||
|
</h1>
|
||||||
|
<p class="ks-job-title">
|
||||||
|
<t t-if="state.employee.job_id">
|
||||||
|
<t t-esc="state.employee.job_id[1]"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.job_id">
|
||||||
|
Add Job Title
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<p class="ks-joined">
|
||||||
|
<t t-if="state.employee.doj">
|
||||||
|
Joined <t t-esc="state.employee.current_company_exp"/> ago
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.doj">
|
||||||
|
Joined Date: <t t-esc="state.employee.doj"/>
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Birthday :
|
||||||
|
<t t-if="state.employee.birthday">
|
||||||
|
<t t-esc="state.employee.birthday"/>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
--/--/----
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="ks-profile-contact">
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-phone"></i>
|
||||||
|
<t t-if="state.employee.mobile_phone">
|
||||||
|
<t t-esc="state.employee.mobile_phone"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.mobile_phone">
|
||||||
|
---
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-envelope"></i>
|
||||||
|
<t t-if="state.employee.work_email">
|
||||||
|
<t t-esc="state.employee.work_email"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.work_email">
|
||||||
|
---
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-home"></i> Address:
|
||||||
|
<t t-if="state.employee.private_street">
|
||||||
|
<t t-esc="state.employee.private_street"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!state.employee.private_street">
|
||||||
|
---
|
||||||
|
</t>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ks-stat-att" t-on-click="attendance_sign_in_out">
|
||||||
|
<t t-if="state.employee.attendance_state == 'checked_out'">
|
||||||
|
<div class="ks-stat-atticon">
|
||||||
|
<i class="fa fa-sign-in"></i>
|
||||||
|
</div>
|
||||||
|
<div class="ks-stat-attcontent">
|
||||||
|
<p>Check In</p>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-if="state.employee.attendance_state == 'checked_in'">
|
||||||
|
<div class="ks-stat-atticon">
|
||||||
|
<i class="fa fa-sign-out"></i>
|
||||||
|
</div>
|
||||||
|
<div class="ks-stat-attcontent">
|
||||||
|
<p>Check Out</p>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
||||||
|
|
@ -6,17 +6,17 @@
|
||||||
<div class="row" style="min-height: 60vh;">
|
<div class="row" style="min-height: 60vh;">
|
||||||
<div class="col-6 d-flex flex-column align-items-stretch chat_explain_ai">
|
<div class="col-6 d-flex flex-column align-items-stretch chat_explain_ai">
|
||||||
|
|
||||||
<t t-if="props.ks_dashboard_item_type === 'ks_tile'">
|
<!-- <t t-if="props.ks_dashboard_item_type === 'ks_tile'">-->
|
||||||
<Ksdashboardtile item="props.item"
|
<!-- <Ksdashboardtile item="props.item"-->
|
||||||
dashboard_data="props.dashboard_data"
|
<!-- dashboard_data="props.dashboard_data"-->
|
||||||
ksdatefilter="props.ksdatefilter"
|
<!-- ksdatefilter="props.ksdatefilter"-->
|
||||||
pre_defined_filter="props.pre_defined_filter"
|
<!-- pre_defined_filter="props.pre_defined_filter"-->
|
||||||
custom_filter="props.custom_filter"
|
<!-- custom_filter="props.custom_filter"-->
|
||||||
hideButtons="0"
|
<!-- hideButtons="0"-->
|
||||||
on_dialog="true"
|
<!-- on_dialog="true"-->
|
||||||
ks_speak="props.ks_speak"/>
|
<!-- ks_speak="props.ks_speak"/>-->
|
||||||
</t>
|
<!-- </t>-->
|
||||||
<t t-elif="props.ks_dashboard_item_type === 'ks_kpi'">
|
<t t-if="props.ks_dashboard_item_type === 'ks_kpi'">
|
||||||
<Ksdashboardkpiview item="props.item"
|
<Ksdashboardkpiview item="props.item"
|
||||||
dashboard_data="props.dashboard_data"
|
dashboard_data="props.dashboard_data"
|
||||||
ksdatefilter="props.ksdatefilter"
|
ksdatefilter="props.ksdatefilter"
|
||||||
|
|
|
||||||
|
|
@ -938,6 +938,9 @@
|
||||||
<t t-elif="items.ks_dashboard_item_type === 'ks_to_do'">
|
<t t-elif="items.ks_dashboard_item_type === 'ks_to_do'">
|
||||||
<Ksdashboardtodo item="items" hideButtons="1" dashboard_data="ks_dashboard_data" explain_ai_whole="explain_ai_whole"/>
|
<Ksdashboardtodo item="items" hideButtons="1" dashboard_data="ks_dashboard_data" explain_ai_whole="explain_ai_whole"/>
|
||||||
</t>
|
</t>
|
||||||
|
<t t-elif="items.ks_dashboard_item_type === 'ks_profile'">
|
||||||
|
<Ksdashboardprofile item="items" hideButtons="1" on_dialog="on_dialog" dashboard_data="ks_dashboard_data" />
|
||||||
|
</t>
|
||||||
<t t-else="">
|
<t t-else="">
|
||||||
<Ksdashboardgraph item="items" hideButtons="1" explain_ai_whole="explain_ai_whole" dashboard_data="ks_dashboard_data" ksdatefilter="state.ksDateFilterSelection" pre_defined_filter = "state.pre_defined_filter" custom_filter="state.custom_filter" ks_speak="(ev)=>this.speak_once(ev,items)"/>
|
<Ksdashboardgraph item="items" hideButtons="1" explain_ai_whole="explain_ai_whole" dashboard_data="ks_dashboard_data" ksdatefilter="state.ksDateFilterSelection" pre_defined_filter = "state.pre_defined_filter" custom_filter="state.custom_filter" ks_speak="(ev)=>this.speak_once(ev,items)"/>
|
||||||
</t>
|
</t>
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@
|
||||||
class="w-100"
|
class="w-100"
|
||||||
widget="ks_dashboard_graph_preview"
|
widget="ks_dashboard_graph_preview"
|
||||||
invisible="ks_dashboard_item_type in
|
invisible="ks_dashboard_item_type in
|
||||||
['ks_to_do', 'ks_tile', 'ks_list_view', 'ks_kpi', 'ks_map_view', 'ks_funnel_chart', 'ks_bullet_chart', 'ks_kpi']"/>
|
['ks_to_do', 'ks_tile', 'ks_list_view', 'ks_kpi', 'ks_map_view', 'ks_funnel_chart', 'ks_bullet_chart', 'ks_kpi', 'ks_profile']"/>
|
||||||
<field name="ks_list_view_preview" class="w-100 encapsulated-list-preview"
|
<field name="ks_list_view_preview" class="w-100 encapsulated-list-preview"
|
||||||
widget="ks_dashboard_list_view_preview"
|
widget="ks_dashboard_list_view_preview"
|
||||||
invisible="ks_dashboard_item_type != 'ks_list_view'"/>
|
invisible="ks_dashboard_item_type != 'ks_list_view'"/>
|
||||||
|
|
@ -240,10 +240,19 @@
|
||||||
<field name="ks_map_preview" string="Map Preview"
|
<field name="ks_map_preview" string="Map Preview"
|
||||||
widget="ks_dashboard_map_preview" class="flex-grow-1 w-100"
|
widget="ks_dashboard_map_preview" class="flex-grow-1 w-100"
|
||||||
invisible="ks_dashboard_item_type != 'ks_map_view'"/>
|
invisible="ks_dashboard_item_type != 'ks_map_view'"/>
|
||||||
|
|
||||||
|
<field name="ks_profile_preview" string="Profile Preview"
|
||||||
|
widget="ks_profile_preview" class="flex-grow-1 w-100"
|
||||||
|
invisible="ks_dashboard_item_type != 'ks_profile'"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="encapsulated-input-group col-xl-7 col-lg-6">
|
<div class="col-6 gap-2 d-flex flex-column" invisible="ks_dashboard_item_type != 'ks_profile'">
|
||||||
|
<label for="name" string="Name" class="o_form_label"/>
|
||||||
|
<field name="name" required="1" placeholder="Enter Name" class="form-control form-input-box w-100"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="encapsulated-input-group col-xl-7 col-lg-6" invisible="ks_dashboard_item_type == 'ks_profile'">
|
||||||
<div class="chart-form-detail row">
|
<div class="chart-form-detail row">
|
||||||
<div class="col-6 gap-2 d-flex flex-column">
|
<div class="col-6 gap-2 d-flex flex-column">
|
||||||
<label for="name" string="Name" class="o_form_label"/>
|
<label for="name" string="Name" class="o_form_label"/>
|
||||||
|
|
@ -267,7 +276,7 @@
|
||||||
<field name="ks_model_id" placeholder="Enter Model Name"
|
<field name="ks_model_id" placeholder="Enter Model Name"
|
||||||
class="form-control form-input-box encapsulated-form-arrow bg-white"
|
class="form-control form-input-box encapsulated-form-arrow bg-white"
|
||||||
options="{'no_create': True, 'no_create_edit':True, 'no_open': True}" nolabel="1"
|
options="{'no_create': True, 'no_create_edit':True, 'no_open': True}" nolabel="1"
|
||||||
context="{'current_id': id}" required="ks_dashboard_item_type != 'ks_to_do' and data_source == 'odoo'"
|
context="{'current_id': id}" required="ks_dashboard_item_type not in ['ks_to_do','ks_profile'] and data_source == 'odoo'"
|
||||||
invisible="ks_data_calculation_type == 'query' or data_source != 'odoo' or ks_dashboard_item_type not in
|
invisible="ks_data_calculation_type == 'query' or data_source != 'odoo' or ks_dashboard_item_type not in
|
||||||
['ks_kpi','ks_radar_view','ks_flower_view','ks_tile','ks_bar_chart','ks_horizontalBar_chart','ks_line_chart','ks_area_chart','ks_pie_chart',
|
['ks_kpi','ks_radar_view','ks_flower_view','ks_tile','ks_bar_chart','ks_horizontalBar_chart','ks_line_chart','ks_area_chart','ks_pie_chart',
|
||||||
'ks_doughnut_chart','ks_polarArea_chart','ks_list_view','ks_scatter_chart','ks_radialBar_chart','ks_funnel_chart','ks_bullet_chart','ks_map_view']"
|
'ks_doughnut_chart','ks_polarArea_chart','ks_list_view','ks_scatter_chart','ks_radialBar_chart','ks_funnel_chart','ks_bullet_chart','ks_map_view']"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue