Merge pull request 'srivyn_test' (#15) from srivyn_test into srivyn_uat
Reviewed-on: https://gitea.ftprotech.in/administrator/odoo18/pulls/15
|
|
@ -234,7 +234,7 @@ class HRApplicant(models.Model):
|
|||
marital = fields.Selection(
|
||||
selection='_get_marital_status_selection',
|
||||
string='Marital Status',
|
||||
groups="hr.group_hr_user",
|
||||
groups='hr_recruitment.group_hr_recruitment_user',
|
||||
default='single',
|
||||
required=True,
|
||||
tracking=True)
|
||||
|
|
|
|||
|
|
@ -36,5 +36,6 @@ access_applicant_stage_comment_wizard,applicant.stage.comment.wizard.user,model_
|
|||
access_hr_application_public,hr.applicant.public.access,hr_recruitment.model_hr_applicant,base.group_public,1,0,0,0
|
||||
access_hr_application_group_hr,hr.applicant.hr.access,hr_recruitment.model_hr_applicant,hr.group_hr_manager,1,1,0,0
|
||||
access_applicant_request_forms_hr_user,access.applicant.request.forms.hr.user,model_applicant_request_forms,hr.group_hr_user,1,1,1,1
|
||||
access_applicant_request_forms_user,access.applicant.request.forms.user,model_applicant_request_forms,base.group_user,1,1,0,0
|
||||
access_hr_skill,access.hr.skill.user,hr_skills.model_hr_skill,base.group_public,1,0,0,0
|
||||
|
||||
|
|
|
|||
|
|
|
@ -124,23 +124,33 @@ class HrmsEmployeeDashboard(http.Controller):
|
|||
|
||||
def _leave_balances(self, employee):
|
||||
LeaveType = request.env["hr.leave.type"].sudo()
|
||||
Allocation = request.env["hr.leave.allocation"].sudo()
|
||||
Leave = request.env["hr.leave"].sudo()
|
||||
employee = employee.sudo()
|
||||
leave_types = LeaveType.search([("active", "=", True)], order="sequence, name")
|
||||
allocation_data = leave_types.get_allocation_data(employee)[employee]
|
||||
allocation_data_by_type = {
|
||||
leave_type_id: data
|
||||
for _name, data, _requires_allocation, leave_type_id in allocation_data
|
||||
}
|
||||
balances = []
|
||||
for leave_type in LeaveType.search([("active", "=", True)], order="sequence, name"):
|
||||
allocations = Allocation.search([
|
||||
("employee_id", "=", employee.id),
|
||||
("holiday_status_id", "=", leave_type.id),
|
||||
("state", "=", "validate"),
|
||||
])
|
||||
leaves = Leave.search([
|
||||
("employee_id", "=", employee.id),
|
||||
("holiday_status_id", "=", leave_type.id),
|
||||
("state", "in", ["confirm", "validate1", "validate"]),
|
||||
])
|
||||
allocated = sum(allocations.mapped("number_of_days"))
|
||||
taken = sum(leaves.filtered(lambda leave: leave.state == "validate").mapped("number_of_days"))
|
||||
planned = sum(leaves.filtered(lambda leave: leave.state in ("confirm", "validate1")).mapped("number_of_days"))
|
||||
for leave_type in leave_types:
|
||||
if leave_type.requires_allocation == "yes":
|
||||
data = allocation_data_by_type.get(leave_type.id, {})
|
||||
allocated = data.get("max_leaves", 0)
|
||||
taken = data.get("leaves_taken", 0)
|
||||
planned = data.get("leaves_requested", 0)
|
||||
remaining = data.get("virtual_remaining_leaves", 0)
|
||||
else:
|
||||
leaves = Leave.search([
|
||||
("employee_id", "=", employee.id),
|
||||
("holiday_status_id", "=", leave_type.id),
|
||||
("state", "in", ["confirm", "validate1", "validate"]),
|
||||
])
|
||||
allocated = 0
|
||||
taken = sum(leaves.filtered(lambda leave: leave.state == "validate").mapped("number_of_days"))
|
||||
planned = sum(leaves.filtered(lambda leave: leave.state in ("confirm", "validate1")).mapped("number_of_days"))
|
||||
remaining = 0
|
||||
chart_total = max(allocated, taken + planned + max(remaining, 0), 1)
|
||||
if allocated or taken or planned or leave_type.requires_allocation == "no":
|
||||
balances.append({
|
||||
"id": leave_type.id,
|
||||
|
|
@ -148,7 +158,10 @@ class HrmsEmployeeDashboard(http.Controller):
|
|||
"allocated": round(allocated, 2),
|
||||
"taken": round(taken, 2),
|
||||
"planned": round(planned, 2),
|
||||
"remaining": round(allocated - taken - planned, 2) if leave_type.requires_allocation != "no" else 0,
|
||||
"remaining": round(remaining, 2),
|
||||
"taken_percent": round((taken / chart_total) * 100, 2),
|
||||
"planned_percent": round((planned / chart_total) * 100, 2),
|
||||
"remaining_percent": round((max(remaining, 0) / chart_total) * 100, 2),
|
||||
"requires_allocation": leave_type.requires_allocation,
|
||||
})
|
||||
return balances
|
||||
|
|
@ -173,35 +186,35 @@ class HrmsEmployeeDashboard(http.Controller):
|
|||
def _get_public_holidays(self, employee, month_start, month_end):
|
||||
start_dt = datetime.combine(month_start, time.min)
|
||||
end_dt = datetime.combine(month_end, time.max)
|
||||
|
||||
calendar = employee.resource_calendar_id or employee.company_id.resource_calendar_id
|
||||
holidays = request.env["resource.calendar.leaves"].sudo().search([
|
||||
("date_from", "<=", end_dt),
|
||||
("date_to", ">=", start_dt),
|
||||
("company_id", "in", [False, employee.company_id.id]),
|
||||
("resource_id", "=", False), # Only company/public holidays
|
||||
], order="date_from asc")
|
||||
return holidays.filtered(lambda holiday: (
|
||||
(not holiday.resource_id or holiday.resource_id == employee.resource_id)
|
||||
and (not holiday.calendar_id or holiday.calendar_id == calendar)
|
||||
))
|
||||
if calendar:
|
||||
holidays = holidays.filtered(
|
||||
lambda h: not h.calendar_id or h.calendar_id == calendar
|
||||
)
|
||||
return holidays
|
||||
|
||||
def _attendance_calendar(self, month_start, month_end, attendances, leaves, public_holidays, calendar_view="monthly"):
|
||||
if calendar_view == "yearly":
|
||||
return self._yearly_attendance_calendar(month_start, month_end, attendances, leaves, public_holidays)
|
||||
|
||||
today = fields.Date.context_today(request.env.user)
|
||||
attendance_by_day = defaultdict(float)
|
||||
for attendance in attendances:
|
||||
day = fields.Datetime.context_timestamp(request.env.user, attendance.check_in).date()
|
||||
attendance_by_day[day] += attendance.worked_hours or 0.0
|
||||
attendance_by_day = self._attendance_hours_by_day(attendances)
|
||||
|
||||
leave_by_day = self._days_from_date_range_records(leaves, "request_date_from", "request_date_to", "holiday_status_id")
|
||||
leave_by_day = self._leave_days(leaves)
|
||||
holiday_by_day = self._days_from_datetime_range_records(public_holidays, "date_from", "date_to")
|
||||
|
||||
days = []
|
||||
cursor = month_start
|
||||
if calendar_view == "monthly":
|
||||
cursor = month_start - timedelta(days=(month_start.weekday() + 1) % 7)
|
||||
end_cursor = month_end + timedelta(days=(5 - month_end.weekday()) % 7)
|
||||
cursor = month_start - timedelta(days=month_start.weekday())
|
||||
end_cursor = month_end + timedelta(days=(6 - month_end.weekday()))
|
||||
else:
|
||||
end_cursor = month_end
|
||||
|
||||
|
|
@ -209,34 +222,91 @@ class HrmsEmployeeDashboard(http.Controller):
|
|||
outside_period = cursor < month_start or cursor > month_end
|
||||
status = "future" if cursor > today else "absent"
|
||||
label = ""
|
||||
hours = round(attendance_by_day.get(cursor, 0.0), 2)
|
||||
attendance_hours = attendance_by_day.get(cursor, {})
|
||||
hours = round(attendance_hours.get("worked_hours", 0.0), 2)
|
||||
break_hours = round(attendance_hours.get("break_hours", 0.0), 2)
|
||||
has_worked_hours = hours > 0.004
|
||||
is_holiday = cursor in holiday_by_day
|
||||
is_leave = cursor in leave_by_day
|
||||
is_half_day_leave = bool(leave_by_day.get(cursor, {}).get("is_half_day"))
|
||||
is_weekend = cursor.weekday() in (5, 6)
|
||||
expected_hours = 0.0
|
||||
if not outside_period and not is_holiday and not (is_weekend and not has_worked_hours):
|
||||
expected_hours = self._expected_hours_for_day(request.env.user.employee_id.sudo(), cursor)
|
||||
leave_hours = expected_hours if is_leave else 0.0
|
||||
show_metrics = (
|
||||
has_worked_hours
|
||||
or (
|
||||
not is_weekend
|
||||
and not is_holiday
|
||||
and (not is_leave or is_half_day_leave)
|
||||
)
|
||||
)
|
||||
if outside_period:
|
||||
status = "empty"
|
||||
elif hours:
|
||||
status = "present"
|
||||
elif cursor in holiday_by_day:
|
||||
show_metrics = False
|
||||
elif is_holiday:
|
||||
status = "holiday"
|
||||
label = holiday_by_day[cursor]
|
||||
elif cursor in leave_by_day:
|
||||
show_metrics = has_worked_hours
|
||||
elif is_leave:
|
||||
status = "leave"
|
||||
label = leave_by_day[cursor]
|
||||
elif cursor.weekday() in (5, 6):
|
||||
label = _("Time Off")
|
||||
show_metrics = is_half_day_leave
|
||||
elif has_worked_hours:
|
||||
status = "present"
|
||||
elif is_weekend:
|
||||
status = "weekend"
|
||||
label = _("Weekend")
|
||||
show_metrics = False
|
||||
days.append({
|
||||
"type": "day",
|
||||
"date": cursor.strftime("%Y-%m-%d"),
|
||||
"day": cursor.day,
|
||||
"weekday": cursor.strftime("%a"),
|
||||
"is_weekend": cursor.weekday() in (5, 6),
|
||||
"is_weekend": is_weekend,
|
||||
"outside_period": outside_period,
|
||||
"status": status,
|
||||
"label": label,
|
||||
"show_metrics": show_metrics,
|
||||
"is_half_day_leave": is_half_day_leave,
|
||||
"hours": hours,
|
||||
"worked_hours": hours,
|
||||
"break_hours": break_hours,
|
||||
"expected_hours": round(expected_hours, 2),
|
||||
"leave_hours": round(leave_hours, 2),
|
||||
"balance_hours": round(hours - expected_hours, 2),
|
||||
"worked_display": self._format_hours(hours),
|
||||
"break_display": self._format_hours(break_hours),
|
||||
"expected_display": self._format_hours(expected_hours),
|
||||
"leave_display": self._format_hours(leave_hours),
|
||||
"balance_display": self._format_signed_hours(hours - expected_hours),
|
||||
})
|
||||
cursor += timedelta(days=1)
|
||||
return days
|
||||
|
||||
def _leave_days(self, leaves):
|
||||
result = {}
|
||||
for leave in leaves:
|
||||
start = fields.Date.to_date(leave.request_date_from)
|
||||
end = fields.Date.to_date(leave.request_date_to)
|
||||
is_half_day = self._is_half_day_leave(leave)
|
||||
while start and end and start <= end:
|
||||
result[start] = {
|
||||
"label": _("Time Off"),
|
||||
"is_half_day": is_half_day,
|
||||
}
|
||||
start += timedelta(days=1)
|
||||
return result
|
||||
|
||||
def _is_half_day_leave(self, leave):
|
||||
if "request_unit_half" in leave._fields and leave.request_unit_half:
|
||||
return True
|
||||
if "request_unit_type" in leave._fields and leave.request_unit_type == "half_day":
|
||||
return True
|
||||
if "request_unit" in leave._fields and leave.request_unit == "half_day":
|
||||
return True
|
||||
return bool(leave.number_of_days and leave.number_of_days < 1)
|
||||
|
||||
def _yearly_attendance_calendar(self, range_start, range_end, attendances, leaves, public_holidays):
|
||||
days = self._attendance_calendar(range_start, range_end, attendances, leaves, public_holidays, "monthly")
|
||||
months = []
|
||||
|
|
@ -259,10 +329,59 @@ class HrmsEmployeeDashboard(http.Controller):
|
|||
"leave": counts["leave"],
|
||||
"holiday": counts["holiday"],
|
||||
"hours": round(sum(day["hours"] for day in month_days), 2),
|
||||
"worked_hours": round(sum(day["worked_hours"] for day in month_days), 2),
|
||||
"break_hours": round(sum(day["break_hours"] for day in month_days), 2),
|
||||
"expected_hours": round(sum(day["expected_hours"] for day in month_days), 2),
|
||||
"worked_display": self._format_hours(sum(day["worked_hours"] for day in month_days)),
|
||||
"break_display": self._format_hours(sum(day["break_hours"] for day in month_days)),
|
||||
"expected_display": self._format_hours(sum(day["expected_hours"] for day in month_days)),
|
||||
})
|
||||
cursor += relativedelta(months=1)
|
||||
return months
|
||||
|
||||
def _attendance_hours_by_day(self, attendances):
|
||||
grouped = defaultdict(list)
|
||||
for attendance in attendances:
|
||||
check_in = fields.Datetime.context_timestamp(request.env.user, attendance.check_in)
|
||||
grouped[check_in.date()].append(attendance)
|
||||
|
||||
result = {}
|
||||
for day, day_attendances in grouped.items():
|
||||
sorted_attendances = sorted(day_attendances, key=lambda attendance: attendance.check_in)
|
||||
worked_hours = sum(attendance.worked_hours or 0.0 for attendance in sorted_attendances)
|
||||
break_hours = 0.0
|
||||
for previous, current in zip(sorted_attendances, sorted_attendances[1:]):
|
||||
if previous.check_out and current.check_in:
|
||||
previous_out = fields.Datetime.context_timestamp(request.env.user, previous.check_out)
|
||||
current_in = fields.Datetime.context_timestamp(request.env.user, current.check_in)
|
||||
if current_in > previous_out:
|
||||
break_hours += (current_in - previous_out).total_seconds() / 3600
|
||||
result[day] = {
|
||||
"worked_hours": worked_hours,
|
||||
"break_hours": break_hours,
|
||||
}
|
||||
return result
|
||||
|
||||
def _expected_hours_for_day(self, employee, day):
|
||||
calendar = employee.resource_calendar_id or employee.company_id.resource_calendar_id
|
||||
if not calendar:
|
||||
return 0.0
|
||||
start_dt = datetime.combine(day, time.min)
|
||||
end_dt = datetime.combine(day, time.max)
|
||||
return round(calendar.get_work_hours_count(start_dt, end_dt, compute_leaves=False), 2)
|
||||
|
||||
def _format_hours(self, hours):
|
||||
hours = abs(hours or 0.0)
|
||||
total_minutes = int(round(hours * 60))
|
||||
hour_part, minute_part = divmod(total_minutes, 60)
|
||||
if minute_part:
|
||||
return "%sh %02dm" % (hour_part, minute_part)
|
||||
return "%sh" % hour_part
|
||||
|
||||
def _format_signed_hours(self, hours):
|
||||
sign = "+" if (hours or 0.0) >= 0 else "-"
|
||||
return "%s%s" % (sign, self._format_hours(hours))
|
||||
|
||||
def _days_from_date_range_records(self, records, start_field, end_field, label_field=False):
|
||||
result = {}
|
||||
for record in records:
|
||||
|
|
@ -285,16 +404,53 @@ class HrmsEmployeeDashboard(http.Controller):
|
|||
return result
|
||||
|
||||
def _attendance_summary(self, month_start, month_end, attendances, leaves, public_holidays):
|
||||
days = self._attendance_calendar(month_start, month_end, attendances, leaves, public_holidays)
|
||||
days = self._attendance_calendar(
|
||||
month_start,
|
||||
month_end,
|
||||
attendances,
|
||||
leaves,
|
||||
public_holidays,
|
||||
)
|
||||
|
||||
counts = defaultdict(int)
|
||||
|
||||
expected_hours = 0.0
|
||||
worked_hours = 0.0
|
||||
break_hours = 0.0
|
||||
leave_hours = 0.0
|
||||
|
||||
for day in days:
|
||||
if day["outside_period"]:
|
||||
continue
|
||||
|
||||
counts[day["status"]] += 1
|
||||
|
||||
expected_hours += day["expected_hours"]
|
||||
worked_hours += day["worked_hours"]
|
||||
break_hours += day["break_hours"]
|
||||
leave_hours += day["leave_hours"]
|
||||
|
||||
remaining_hours = expected_hours - worked_hours - leave_hours
|
||||
|
||||
return {
|
||||
"present": counts["present"],
|
||||
"absent": counts["absent"],
|
||||
"leave": counts["leave"],
|
||||
"holiday": counts["holiday"],
|
||||
"hours": round(sum(attendances.mapped("worked_hours")), 2),
|
||||
|
||||
"hours": round(worked_hours, 2),
|
||||
|
||||
"worked_hours": round(worked_hours, 2),
|
||||
"break_hours": round(break_hours, 2),
|
||||
"expected_hours": round(expected_hours, 2),
|
||||
"leave_hours": round(leave_hours, 2),
|
||||
"remaining_hours": round(remaining_hours, 2),
|
||||
|
||||
"worked_display": self._format_hours(worked_hours),
|
||||
"break_display": self._format_hours(break_hours),
|
||||
"expected_display": self._format_hours(expected_hours),
|
||||
"leave_display": self._format_hours(leave_hours),
|
||||
"remaining_display": self._format_signed_hours(remaining_hours),
|
||||
}
|
||||
|
||||
def _holiday_list(self, holidays):
|
||||
|
|
@ -317,25 +473,15 @@ class HrmsEmployeeDashboard(http.Controller):
|
|||
totals[month.strftime("%Y-%m")] += 0.0
|
||||
month += relativedelta(months=1)
|
||||
|
||||
HrExpense = request.env["hr.expense"].sudo()
|
||||
emp_expenses = HrExpense.search([
|
||||
expenses = request.env["hr.expense"].sudo().search([
|
||||
("employee_id", "=", employee.id),
|
||||
("date", ">=", date_from),
|
||||
("date", "<=", date_to),
|
||||
])
|
||||
for expense in emp_expenses:
|
||||
totals[expense.date.strftime("%Y-%m")] += expense.total_amount or 0.0
|
||||
state_totals[expense.state or "draft"] += expense.total_amount or 0.0
|
||||
|
||||
if request.env.registry.get("hr.expense"):
|
||||
hr_expenses = request.env["hr.expense"].sudo().search([
|
||||
("employee_id", "=", employee.id),
|
||||
("date", ">=", date_from),
|
||||
("date", "<=", date_to),
|
||||
])
|
||||
for expense in hr_expenses:
|
||||
totals[expense.date.strftime("%Y-%m")] += expense.total_amount_currency or expense.total_amount or 0.0
|
||||
state_totals[expense.state or "draft"] += expense.total_amount_currency or expense.total_amount or 0.0
|
||||
for expense in expenses:
|
||||
amount = self._expense_amount(expense)
|
||||
totals[expense.date.strftime("%Y-%m")] += amount
|
||||
state_totals[expense.state or "draft"] += amount
|
||||
|
||||
return {
|
||||
"labels": labels,
|
||||
|
|
@ -345,6 +491,11 @@ class HrmsEmployeeDashboard(http.Controller):
|
|||
"currency": employee.company_id.currency_id.symbol or "",
|
||||
}
|
||||
|
||||
def _expense_amount(self, expense):
|
||||
if "total_amount_currency" in expense._fields and expense.total_amount_currency:
|
||||
return expense.total_amount_currency
|
||||
return expense.total_amount or 0.0
|
||||
|
||||
def _month_keys(self, first_month, last_month):
|
||||
keys = []
|
||||
month = first_month
|
||||
|
|
|
|||
|
|
@ -184,8 +184,11 @@
|
|||
|
||||
.hrms-kpi.present strong { color: #16a34a; }
|
||||
.hrms-kpi.absent strong { color: #dc2626; }
|
||||
.hrms-kpi.break strong { color: #2563eb; }
|
||||
.hrms-kpi.leave strong,
|
||||
.hrms-kpi.holiday strong { color: #f97316; }
|
||||
.hrms-kpi.remaining.positive strong { color: #16a34a; }
|
||||
.hrms-kpi.remaining.negative strong { color: #dc2626; }
|
||||
|
||||
.hrms-grid {
|
||||
display: grid;
|
||||
|
|
@ -230,65 +233,217 @@
|
|||
|
||||
.hrms-calendar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, minmax(82px, 1fr));
|
||||
gap: 10px;
|
||||
grid-template-columns: repeat(7, minmax(130px, 1fr));
|
||||
gap: 0;
|
||||
overflow-x: auto;
|
||||
border: 1px solid #dbe3ed;
|
||||
border-radius: 8px;
|
||||
background: #dbe3ed;
|
||||
}
|
||||
|
||||
.hrms-calendar-weekdays {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, minmax(82px, 1fr));
|
||||
gap: 10px;
|
||||
margin-bottom: 8px;
|
||||
grid-template-columns: repeat(7, minmax(130px, 1fr));
|
||||
gap: 0;
|
||||
overflow-x: auto;
|
||||
border: 1px solid #dbe3ed;
|
||||
border-bottom: 0;
|
||||
border-radius: 8px 8px 0 0;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.hrms-calendar-weekdays span {
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
padding: 10px 8px;
|
||||
color: #0f172a;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
border-right: 1px solid #dbe3ed;
|
||||
}
|
||||
|
||||
.hrms-calendar-weekdays span:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.hrms-calendar.yearly {
|
||||
grid-template-columns: repeat(4, minmax(160px, 1fr));
|
||||
gap: 10px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.hrms-day {
|
||||
min-height: 82px;
|
||||
padding: 8px;
|
||||
min-height: 132px;
|
||||
padding: 10px;
|
||||
border: 0;
|
||||
border-right: 1px solid #dbe3ed;
|
||||
border-bottom: 1px solid #dbe3ed;
|
||||
border-radius: 0;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hrms-calendar.yearly .hrms-day {
|
||||
min-height: 126px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.hrms-day span,
|
||||
.hrms-day small {
|
||||
display: block;
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.hrms-day strong {
|
||||
display: block;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
line-height: 31px;
|
||||
margin-top: 6px;
|
||||
.hrms-day-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 6px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.hrms-day-top strong {
|
||||
color: #0f172a;
|
||||
font-size: 13px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.hrms-day-top strong span {
|
||||
display: inline;
|
||||
margin-left: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hrms-day-badge {
|
||||
max-width: 76px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
background: #eef2ff;
|
||||
color: #4338ca;
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hrms-day-balance {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 10px 0 8px;
|
||||
border-radius: 999px;
|
||||
text-align: center;
|
||||
border: 2px solid #cbd5e1;
|
||||
color: #0f172a;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.hrms-day.present strong { border-color: #16a34a; background: #dcfce7; }
|
||||
.hrms-day.absent strong { border-color: #dc2626; color: #dc2626; background: #fff; }
|
||||
.hrms-day.leave strong,
|
||||
.hrms-day.holiday strong { border-color: #f97316; background: #ffedd5; color: #9a3412; }
|
||||
.hrms-day.weekend strong { border-color: #94a3b8; background: #f1f5f9; color: #475569; }
|
||||
.hrms-day-balance.positive {
|
||||
background: #dcfce7;
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.hrms-day-balance.negative {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.hrms-day-message {
|
||||
min-height: 76px;
|
||||
margin-top: 10px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hrms-day-message-icon {
|
||||
color: inherit;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.hrms-day-message strong {
|
||||
color: inherit;
|
||||
font-size: 13px;
|
||||
line-height: 1.25;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.hrms-day-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.hrms-day-metrics div {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.hrms-day-metrics span {
|
||||
display: block;
|
||||
color: #64748b;
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.hrms-day-metrics strong {
|
||||
display: block;
|
||||
margin-top: 3px;
|
||||
color: #0f172a;
|
||||
font-size: 13px;
|
||||
line-height: 1.15;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hrms-calendar-month-stats {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.hrms-calendar-month-stats small {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.hrms-day.present { box-shadow: inset 0 3px 0 #22c55e; }
|
||||
.hrms-day.absent { box-shadow: inset 0 3px 0 #ef4444; }
|
||||
.hrms-day.leave {
|
||||
background: #fff5f5;
|
||||
box-shadow: inset 0 3px 0 #ef4444;
|
||||
}
|
||||
.hrms-day.leave .hrms-day-message {
|
||||
background: #fee2e2;
|
||||
color: #b91c1c;
|
||||
border: 1px solid #fecaca;
|
||||
}
|
||||
.hrms-day.holiday {
|
||||
background: #f8fafc;
|
||||
box-shadow: inset 0 3px 0 #94a3b8;
|
||||
}
|
||||
.hrms-day.holiday .hrms-day-message {
|
||||
background: #e5e7eb;
|
||||
color: #334155;
|
||||
border: 1px solid #cbd5e1;
|
||||
}
|
||||
.hrms-day.weekend {
|
||||
background: #f8fafc;
|
||||
box-shadow: none;
|
||||
}
|
||||
.hrms-day.weekend .hrms-day-message {
|
||||
min-height: 58px;
|
||||
background: transparent;
|
||||
color: #94a3b8;
|
||||
border: 1px dashed #e2e8f0;
|
||||
}
|
||||
.hrms-day.future { opacity: 0.55; }
|
||||
.hrms-day.empty {
|
||||
background: #f8fafc;
|
||||
border-style: dashed;
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
|
|
@ -318,6 +473,9 @@
|
|||
}
|
||||
|
||||
.hrms-leave-tile span {
|
||||
display: inline-block;
|
||||
min-width: 64px;
|
||||
margin-right: 10px;
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
|
@ -327,6 +485,91 @@
|
|||
color: #0f172a;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.hrms-leave-graph {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.hrms-leave-graph-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(140px, 190px) minmax(180px, 1fr);
|
||||
gap: 10px 14px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hrms-leave-graph-label strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.hrms-leave-graph-label span {
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.hrms-leave-bar {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
background: #e5e7eb;
|
||||
}
|
||||
|
||||
.hrms-leave-bar span {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.hrms-leave-bar-remaining {
|
||||
background: #16a34a;
|
||||
}
|
||||
|
||||
.hrms-leave-bar-taken {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.hrms-leave-bar-planned {
|
||||
background: #f59e0b;
|
||||
}
|
||||
|
||||
.hrms-leave-legend {
|
||||
grid-column: 2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 14px;
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.hrms-leave-legend span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.hrms-leave-legend i {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.hrms-leave-legend i.remaining {
|
||||
background: #16a34a;
|
||||
}
|
||||
|
||||
.hrms-leave-legend i.taken {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.hrms-leave-legend i.planned {
|
||||
background: #f59e0b;
|
||||
}
|
||||
|
||||
.hrms-leave-legend b {
|
||||
color: #0f172a;
|
||||
}
|
||||
.hrms-two-charts {
|
||||
display: grid;
|
||||
grid-template-columns: 1.3fr 0.7fr;
|
||||
|
|
@ -398,10 +641,15 @@
|
|||
|
||||
.hrms-employee-grid,
|
||||
.hrms-grid,
|
||||
.hrms-leave-graph-row,
|
||||
.hrms-two-charts {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.hrms-leave-legend {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.hrms-panel.wide {
|
||||
grid-column: span 1;
|
||||
}
|
||||
|
|
@ -416,13 +664,17 @@
|
|||
@media (max-width: 700px) {
|
||||
.hrms-kpi-row,
|
||||
.hrms-equipment-grid,
|
||||
.hrms-calendar,
|
||||
.hrms-calendar.yearly,
|
||||
.hrms-leave-summary,
|
||||
.hrms-custom-dates {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.hrms-calendar,
|
||||
.hrms-calendar-weekdays {
|
||||
grid-template-columns: repeat(7, minmax(118px, 1fr));
|
||||
}
|
||||
|
||||
.hrms-panel-header,
|
||||
.hrms-panel-actions,
|
||||
.hrms-action-buttons {
|
||||
|
|
@ -488,4 +740,4 @@
|
|||
#hrmsExpenseChart,
|
||||
#hrmsExpenseStateChart{
|
||||
min-height:340px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class HrmsEmployeeDashboard extends Component {
|
|||
const monthStart = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
const monthEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0);
|
||||
const weekStart = new Date(today);
|
||||
weekStart.setDate(today.getDate() - today.getDay());
|
||||
weekStart.setDate(today.getDate() - ((today.getDay() + 6) % 7));
|
||||
|
||||
const weekEnd = new Date(weekStart);
|
||||
weekEnd.setDate(weekStart.getDate() + 6);
|
||||
|
|
@ -68,7 +68,6 @@ class HrmsEmployeeDashboard extends Component {
|
|||
return;
|
||||
}
|
||||
this.state.data = response;
|
||||
// setTimeout(() => this.initCharts(), 100);
|
||||
const expenses = response.expenses || {};
|
||||
const total =
|
||||
(expenses.series || []).reduce(
|
||||
|
|
@ -76,11 +75,7 @@ class HrmsEmployeeDashboard extends Component {
|
|||
0
|
||||
);
|
||||
this.state.expenseCount = total;
|
||||
if (this.state.expenseCount > 0) {
|
||||
setTimeout(() => this.initCharts(), 100);
|
||||
} else {
|
||||
this.destroyCharts();
|
||||
}
|
||||
setTimeout(() => this.initCharts(), 100);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.state.error = "Unable to load employee dashboard.";
|
||||
|
|
@ -107,7 +102,6 @@ class HrmsEmployeeDashboard extends Component {
|
|||
}
|
||||
this.destroyCharts();
|
||||
const leaves = this.state.data.leave_balances || [];
|
||||
debugger;
|
||||
this.renderLeaveChart(leaves);
|
||||
this.renderExpenseChart();
|
||||
this.renderExpenseStateChart();
|
||||
|
|
@ -135,17 +129,18 @@ class HrmsEmployeeDashboard extends Component {
|
|||
}
|
||||
|
||||
renderLeaveChart(leaves) {
|
||||
const allocatedLeaves = leaves.filter((leave) => leave.requires_allocation === "yes");
|
||||
this.chartBase("#hrmsLeaveChart", {
|
||||
chart: { type: "bar" },
|
||||
series: [
|
||||
{ name: "Remaining", data: leaves.map((leave) => leave.remaining) },
|
||||
{ name: "Taken", data: leaves.map((leave) => leave.taken) },
|
||||
{ name: "Planned", data: leaves.map((leave) => leave.planned) },
|
||||
{ name: "Remaining", data: allocatedLeaves.map((leave) => Number(leave.remaining || 0)) },
|
||||
{ name: "Taken", data: allocatedLeaves.map((leave) => Number(leave.taken || 0)) },
|
||||
{ name: "Planned", data: allocatedLeaves.map((leave) => Number(leave.planned || 0)) },
|
||||
],
|
||||
colors: ["#16a34a", "#2563eb", "#f59e0b"],
|
||||
plotOptions: { bar: { borderRadius: 4, columnWidth: "50%" } },
|
||||
dataLabels: { enabled: false },
|
||||
xaxis: { categories: leaves.map((leave) => leave.name), labels: { rotate: -25, trim: true } },
|
||||
xaxis: { categories: allocatedLeaves.map((leave) => leave.name), labels: { rotate: -25, trim: true } },
|
||||
yaxis: { min: 0, forceNiceScale: true },
|
||||
});
|
||||
}
|
||||
|
|
@ -155,7 +150,6 @@ class HrmsEmployeeDashboard extends Component {
|
|||
return;
|
||||
}
|
||||
const expenses = this.state.data.expenses;
|
||||
debugger;
|
||||
this.chartBase("#hrmsExpenseChart", {
|
||||
chart: {
|
||||
type: "area",
|
||||
|
|
@ -183,8 +177,6 @@ class HrmsEmployeeDashboard extends Component {
|
|||
type: "donut",
|
||||
events: {
|
||||
dataPointSelection: (event, chartContext, config) => {
|
||||
debugger;
|
||||
const stateIndex = chartContext.dataPointIndex;
|
||||
const state = expenses.state_labels[config.dataPointIndex];
|
||||
this.openExpenses(state);
|
||||
},
|
||||
|
|
@ -242,7 +234,7 @@ class HrmsEmployeeDashboard extends Component {
|
|||
this.state.calendarDateTo = this.formatDate(new Date(today.getFullYear(), 11, 31));
|
||||
} else if (this.state.calendarView === "weekly") {
|
||||
const weekStart = new Date(today);
|
||||
weekStart.setDate(weekStart.getDate() - weekStart.getDay());
|
||||
weekStart.setDate(weekStart.getDate() - ((weekStart.getDay() + 6) % 7));
|
||||
const weekEnd = new Date(weekStart);
|
||||
weekEnd.setDate(weekStart.getDate() + 6);
|
||||
this.state.calendarDateFrom = this.formatDate(weekStart);
|
||||
|
|
@ -400,7 +392,6 @@ class HrmsEmployeeDashboard extends Component {
|
|||
}
|
||||
|
||||
openExpenses(state = false) {
|
||||
debugger;
|
||||
const domain = [["employee_id", "=", this.state.data.employee.id]];
|
||||
if (state) {
|
||||
domain.push(["state", "=", state.toLowerCase()]);
|
||||
|
|
|
|||
|
|
@ -74,11 +74,14 @@
|
|||
</section>
|
||||
|
||||
<section class="hrms-kpi-row">
|
||||
<div class="hrms-kpi present"><span>Present</span><strong t-esc="state.data.attendance_summary.present"/></div>
|
||||
<div class="hrms-kpi absent"><span>No Check-In</span><strong t-esc="state.data.attendance_summary.absent"/></div>
|
||||
<div class="hrms-kpi leave"><span>Leaves</span><strong t-esc="state.data.attendance_summary.leave"/></div>
|
||||
<div class="hrms-kpi holiday"><span>Holidays</span><strong t-esc="state.data.attendance_summary.holiday"/></div>
|
||||
<div class="hrms-kpi"><span>Hours</span><strong><t t-esc="state.data.attendance_summary.hours"/>h</strong></div>
|
||||
<div class="hrms-kpi"><span>Expected Hours</span><strong t-esc="state.data.attendance_summary.expected_display"/></div>
|
||||
<div class="hrms-kpi present"><span>Worked Hours</span><strong t-esc="state.data.attendance_summary.worked_display"/></div>
|
||||
<div class="hrms-kpi break"><span>Break Hours</span><strong t-esc="state.data.attendance_summary.break_display"/></div>
|
||||
<div class="hrms-kpi leave"><span>Leave Hours</span><strong t-esc="state.data.attendance_summary.leave_display"/></div>
|
||||
<div t-att-class="'hrms-kpi remaining ' + (state.data.attendance_summary.remaining_hours >= 0 ? 'positive' : 'negative')">
|
||||
<span>Remaining Hours</span>
|
||||
<strong t-esc="state.data.attendance_summary.remaining_display"/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="hrms-grid">
|
||||
|
|
@ -97,30 +100,61 @@
|
|||
</div>
|
||||
</div>
|
||||
<div t-if="state.calendarView !== 'yearly'" class="hrms-calendar-weekdays">
|
||||
<span>Sun</span>
|
||||
<span>Mon</span>
|
||||
<span>Tue</span>
|
||||
<span>Wed</span>
|
||||
<span>Thu</span>
|
||||
<span>Fri</span>
|
||||
<span>Sat</span>
|
||||
<span>Sun</span>
|
||||
</div>
|
||||
<div class="hrms-calendar" t-att-class="state.calendarView === 'yearly' ? 'yearly' : ''">
|
||||
<div t-foreach="state.data.attendance_calendar" t-as="day" t-key="day.date" class="hrms-day" t-att-class="day.status" t-att-title="day.label || day.hours + 'h'">
|
||||
<div t-foreach="state.data.attendance_calendar" t-as="day" t-key="day.date" class="hrms-day" t-att-class="day.status" t-att-title="day.label || day.worked_display">
|
||||
<t t-if="day.status === 'empty'">
|
||||
<span/>
|
||||
</t>
|
||||
<t t-elif="day.type === 'month'">
|
||||
<span t-esc="day.weekday"/>
|
||||
<strong t-esc="day.day"/>
|
||||
<small><t t-esc="day.present"/> present · <t t-esc="day.hours"/>h</small>
|
||||
<small><t t-esc="day.leave"/> leave · <t t-esc="day.holiday"/> holidays</small>
|
||||
<div class="hrms-day-top">
|
||||
<span t-esc="day.weekday"/>
|
||||
<strong t-esc="day.day"/>
|
||||
</div>
|
||||
<div class="hrms-calendar-month-stats">
|
||||
<small><t t-esc="day.present"/> present</small>
|
||||
<small><t t-esc="day.worked_display"/> worked</small>
|
||||
<small><t t-esc="day.break_display"/> break</small>
|
||||
<small><t t-esc="day.leave"/> leave · <t t-esc="day.holiday"/> holidays</small>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-esc="day.weekday"/>
|
||||
<strong t-esc="day.day"/>
|
||||
<small t-if="day.hours"><t t-esc="day.hours"/>h</small>
|
||||
<small t-elif="day.label" t-esc="day.label"/>
|
||||
<div class="hrms-day-top">
|
||||
<strong>
|
||||
<t t-esc="day.day"/>
|
||||
<span t-esc="day.weekday"/>
|
||||
</strong>
|
||||
<span t-if="day.label and day.show_metrics" class="hrms-day-badge" t-esc="day.label"/>
|
||||
</div>
|
||||
<div t-if="!day.show_metrics and day.label" class="hrms-day-message">
|
||||
<span t-if="day.status === 'leave'" class="hrms-day-message-icon"><i class="fa fa-calendar-times-o"/></span>
|
||||
<span t-elif="day.status === 'holiday'" class="hrms-day-message-icon"><i class="fa fa-calendar"/></span>
|
||||
<strong t-esc="day.label || '-'"/>
|
||||
</div>
|
||||
<div t-if="day.show_metrics" t-att-class="'hrms-day-balance ' + (day.balance_hours >= 0 ? 'positive' : 'negative')">
|
||||
<t t-esc="day.balance_display"/>
|
||||
</div>
|
||||
<div t-if="day.show_metrics" class="hrms-day-metrics">
|
||||
<div>
|
||||
<span>Wrk.</span>
|
||||
<strong t-esc="day.worked_display"/>
|
||||
</div>
|
||||
<div>
|
||||
<span>Break</span>
|
||||
<strong t-esc="day.break_display"/>
|
||||
</div>
|
||||
<div>
|
||||
<span>Exp.</span>
|
||||
<strong t-esc="day.expected_display"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -138,11 +172,32 @@
|
|||
<strong t-esc="leave.name"/>
|
||||
<div>
|
||||
<span><b t-esc="leave.remaining"/> Balance</span>
|
||||
<span><b t-esc="leave.taken"/> Taken</span>
|
||||
<span><b t-esc="leave.planned"/> Confirmed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hrms-leave-graph">
|
||||
<div t-foreach="state.data.leave_balances" t-as="leave" t-key="leave.id + '-graph'">
|
||||
<div t-if="leave.requires_allocation === 'yes'" class="hrms-leave-graph-row">
|
||||
<div class="hrms-leave-graph-label">
|
||||
<strong t-esc="leave.name"/>
|
||||
<span><t t-esc="leave.allocated"/> allocated</span>
|
||||
</div>
|
||||
<div class="hrms-leave-bar" role="img" t-att-aria-label="leave.name + ': ' + leave.remaining + ' balance, ' + leave.taken + ' taken, ' + leave.planned + ' confirmed'">
|
||||
<span class="hrms-leave-bar-remaining" t-att-style="'width: ' + leave.remaining_percent + '%'"/>
|
||||
<span class="hrms-leave-bar-taken" t-att-style="'width: ' + leave.taken_percent + '%'"/>
|
||||
<span class="hrms-leave-bar-planned" t-att-style="'width: ' + leave.planned_percent + '%'"/>
|
||||
</div>
|
||||
<div class="hrms-leave-legend">
|
||||
<span><i class="remaining"/>Balance <b t-esc="leave.remaining"/></span>
|
||||
<span><i class="taken"/>Taken <b t-esc="leave.taken"/></span>
|
||||
<span><i class="planned"/>Confirmed <b t-esc="leave.planned"/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="hrmsLeaveChart"/>
|
||||
</section>
|
||||
|
||||
<section class="hrms-panel">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
Most of the files are
|
||||
|
||||
Copyright (c) 2012-TODAY Kanak Infosystems LLP.
|
||||
|
||||
Many files also contain contributions from third
|
||||
parties. In this case the original copyright of
|
||||
the contributions can be traced through the
|
||||
history of the source version control system.
|
||||
|
||||
When that is not the case, the files contain a prominent
|
||||
notice stating the original copyright and applicable
|
||||
license, or come with their own dedicated COPYRIGHT
|
||||
and/or LICENSE file.
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
Odoo Proprietary License v1.0
|
||||
|
||||
This software and associated files (the "Software") may only be used (executed,
|
||||
modified, executed after modifications) if you have purchased a valid license
|
||||
from the authors, typically via Odoo Apps, or if you have received a written
|
||||
agreement from the authors of the Software (see the COPYRIGHT file).
|
||||
|
||||
You may develop Odoo modules that use the Software as a library (typically
|
||||
by depending on it, importing it and using its resources), but without copying
|
||||
any source code or material from the Software. You may distribute those
|
||||
modules under the license of your choice, provided that this license is
|
||||
compatible with the terms of the Odoo Proprietary License (For example:
|
||||
LGPL, MIT, or proprietary licenses similar to this one).
|
||||
|
||||
It is forbidden to publish, distribute, sublicense, or sell copies of the Software
|
||||
or modified copies of the Software.
|
||||
|
||||
The above copyright notice and this permission notice must be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Powered by Kanak Infosystems LLP.
|
||||
# © 2020 Kanak Infosystems LLP. (<https://www.kanakinfosystems.com>).
|
||||
|
||||
from . import controller
|
||||
from . import models
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Powered by Kanak Infosystems LLP.
|
||||
# © 2020 Kanak Infosystems LLP. (<https://www.kanakinfosystems.com>).
|
||||
|
||||
{
|
||||
'name': "Background image in Login page",
|
||||
'version': '18.0.1.0',
|
||||
'license': 'OPL-1',
|
||||
'depends': ['base', 'portal'],
|
||||
'category': 'Tools',
|
||||
'author': 'Kanak Infosystems LLP.',
|
||||
'website': "https://www.kanakinfosystems.com",
|
||||
'summary': """Module helps to set background image in Login page. | Background Image | Image | Login | Login Page | Website""",
|
||||
'description': """Module helps to set background image in Login page.""",
|
||||
'data': [
|
||||
'views/res_company.xml',
|
||||
],
|
||||
'images': ['static/description/banner.gif'],
|
||||
'sequence': 1
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Powered by Kanak Infosystems LLP.
|
||||
# © 2020 Kanak Infosystems LLP. (<https://www.kanakinfosystems.com>).
|
||||
|
||||
from . import main
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Powered by Kanak Infosystems LLP.
|
||||
# © 2020 Kanak Infosystems LLP. (<https://www.kanakinfosystems.com>).
|
||||
|
||||
import base64
|
||||
from odoo.http import Controller, request, route
|
||||
from werkzeug.utils import redirect
|
||||
|
||||
DEFAULT_IMAGE = 'login_bg_img_knk/static/src/img/bg.jpg'
|
||||
|
||||
|
||||
class DasboardBackground(Controller):
|
||||
|
||||
@route(['/dashboard'], type='http', auth="public")
|
||||
def dashboard(self, **post):
|
||||
user = request.env.user
|
||||
company = user.company_id
|
||||
if company.bg_image:
|
||||
image = base64.b64decode(company.bg_image)
|
||||
else:
|
||||
return redirect(DEFAULT_IMAGE)
|
||||
|
||||
return request.make_response(
|
||||
image, [('Content-Type', 'image')])
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Powered by Kanak Infosystems LLP.
|
||||
# © 2020 Kanak Infosystems LLP. (<https://www.kanakinfosystems.com>).
|
||||
|
||||
from . import res_company
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Powered by Kanak Infosystems LLP.
|
||||
# © 2020 Kanak Infosystems LLP. (<https://www.kanakinfosystems.com>).
|
||||
|
||||
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
bg_image = fields.Binary(string="Image")
|
||||
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 336 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 201 KiB |
|
After Width: | Height: | Size: 558 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 658 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 2.7 MiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
|
@ -0,0 +1,467 @@
|
|||
<section class="index-banner shadow-sm position-relative mt40" style="border-bottom:4px solid #37bbf9; border-radius: 10px;">
|
||||
<img class="w-100 h-100 position-absolute img-fluid mb16" src="etc/1-background.jpg" style="border-radius: 10px;" />
|
||||
<div class="container p-md-4 p-4 position-relative">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-2 text-center text-md-left">
|
||||
<img src="etc/kanak_logo.png" alt="Kanak Infosystems LLP." class="img img-fluid" style="height: 60px; margin:10px 0">
|
||||
</div>
|
||||
<div class="col-md-2 text-center text-md-left" style="margin-left: auto;padding-right: 10px; padding-left: 10px;">
|
||||
<h6 style="font-size:18px;margin:10px 0">
|
||||
<span class="badge badge-pill badge-light w-md-100 w-auto" style="color:#ffffff; background-color:#f62943; border-radius:0.5rem; padding:1rem;"><i class="fa fa-check"></i> Community </span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="col-md-2 text-center text-md-left" style="padding-right: 10px; padding-left: 10px;">
|
||||
<h6 style="font-size:18px;margin:10px 0">
|
||||
<span class="badge badge-pill badge-light w-md-100 w-auto" style="color:#ffffff; background-color:#dab000; border-radius:0.5rem; padding:1rem"><i class="fa fa-check"></i> Enterprise </span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="col-md-2 text-center text-md-left" style="padding-right: 10px; padding-left: 10px;">
|
||||
<h6 style="font-size:18px;margin:10px 0">
|
||||
<span class="badge badge-pill badge-light w-md-100 w-auto" style="color:#ffffff; background-color:#00c157; border-radius:0.5rem; padding:1rem;"><i class="fa fa-check"></i> Odoo.sh</span>
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner shadow-sm position-relative mt40" style="border-bottom:4px solid #cf6cb3; border-radius: 10px;">
|
||||
<img class="w-100 h-100 position-absolute img-fluid" src="etc/2-background.jpg" style="border-radius: 10px;" />
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<h1 style="font-size: 35px; margin-bottom: 16px; margin-top: 16px;">Background image in Login page</h1>
|
||||
<p style="font-size:18px; line-height:24px;">
|
||||
How cool Would that be, if <b>Background image in Login page</b> module helps to set background image in Login page.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<img src="icon.png" alt="Background image in Login page" class="img img-fluid" style="margin-left: 15.5rem;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner shadow-sm position-relative mt40" style="border-bottom:4px solid #37bbf9; border-radius: 10px;">
|
||||
<img class="w-100 h-100 position-absolute img-fluid" src="etc/1-background.jpg" style="border-radius: 10px;" />
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-12">
|
||||
<h1 style="font-size: 30px; margin-bottom: 16px;">Background image in Login page :-</h1>
|
||||
<p class="fa fa-hand-o-right" style="font-size:18px; line-height:24px;"> Navigate to settings > Companies > Click on image field sections and set an image.</p>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<img src="screenshots/login_bg_img_1.png" alt="Background image in Login page" class="img img-fluid" style="min-height: 280px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner shadow-sm position-relative mt40" style="border-bottom:4px solid #37bbf9; border-radius: 10px;">
|
||||
<img class="w-100 h-100 position-absolute img-fluid" src="etc/1-background.jpg" style="border-radius: 10px;" />
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-12">
|
||||
<p class="fa fa-hand-o-right" style="font-size:18px; line-height:24px;"> Here we can see the backgroun image in login page.</p>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<img src="screenshots/login_bg_img_2.png" alt="Background image in Login page" class="img img-fluid" style="min-height: 280px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner shadow-sm position-relative mt40" style="border-bottom:4px solid #37bbf9; border-radius: 10px;">
|
||||
<img class="w-100 h-100 position-absolute img-fluid" src="etc/1-background.jpg" style="border-radius: 10px;" />
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-12">
|
||||
<p class="fa fa-hand-o-right" style="font-size:18px; line-height:24px;"> Here we can see the background image in website.</p>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<img src="screenshots/login_bg_img_3.png" alt="Background image in Login page" class="img img-fluid" style="min-height: 280px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner mt40">
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row align-items-center justify-content-center text-center">
|
||||
<div class="col-md-12">
|
||||
<h4 class="mb32 oe_slogan" style="font-size: 34px; font-weight: 600;">Key Features</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center justify-content-center">
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="h-100 shadow align-items-center" style="border-radius:15px; min-height: 100px; display: flex; align-items: center;">
|
||||
<div class="d-flex p-3 align-items-center">
|
||||
<img src="etc/keyfeature.png" alt="Background image in Login page" class="img img-fluid" style="padding-right: 1.5rem;">
|
||||
<div>
|
||||
<p class="mb-1" style="font-size:18px; line-height:24px; font-weight: 600;">
|
||||
set background image in Login page.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="h-100 shadow align-items-center" style="border-radius:15px; min-height: 100px; display: flex; align-items: center;">
|
||||
<div class="d-flex p-3 align-items-center">
|
||||
<img src="etc/keyfeature.png" alt="Background image in Login page" class="img img-fluid" style="padding-right: 1.5rem;">
|
||||
<div>
|
||||
<p class="mb-1" style="font-size:18px; line-height:24px; font-weight: 600;">
|
||||
Support Multi Company.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="h-100 shadow align-items-center" style="border-radius:15px; min-height: 100px; display: flex; align-items: center;">
|
||||
<div class="d-flex p-3 align-items-center">
|
||||
<img src="etc/keyfeature.png" alt="Background image in Login page" class="img img-fluid" style="padding-right: 1.5rem;">
|
||||
<div>
|
||||
<p class="mb-1" style="font-size:18px; line-height:24px; font-weight: 600;">
|
||||
No Configurations.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner index-tabs position-relative mt40" style="border-radius: 10px;">
|
||||
<div class="container position-relative">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<ul class="nav nav-tabs justify-content-center bg-white pt-md-2" style="text-align:center; border-bottom: none;" role="tablist" id="myTab">
|
||||
<li class="nav-item" role="presentation" style="border-top-right-radius:10px; border-top-left-radius:10px; background-color:#f0f6f7; margin-right:10px; border:1px solid #ddd; border-bottom:0">
|
||||
<a href="#dep3" role="tab" data-toggle="tab" class="nav-link active" id="dep3-tab" title="" aria-selected="true" style="color:#4F4F4F; font-weight:400; font-size:16px; padding:11px 20px; border-top-left-radius:10px; border-top-right-radius:10px;"><span class="fa fa-user" style="margin-right: 5px;"> </span> Support</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation" style="border-top-right-radius:10px; border-top-left-radius:10px; background-color:#f0f6f7; margin-right:10px; border:1px solid #ddd; border-bottom:0">
|
||||
<a href="#change_log" role="tab" data-toggle="tab" class="nav-link" title="" aria-selected="false" style="color:#4F4F4F; font-weight:400; font-size:16px;padding:11px 20px; border-top-left-radius:10px; border-top-right-radius:10px;"><span class="fa fa-history" style="margin-right: 5px;"></span> Change Log</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation" style="border-top-right-radius:10px; border-top-left-radius:10px; background-color:#f0f6f7; margin-right:10px; border:1px solid #ddd; border-bottom:0">
|
||||
<a href="#dep5" role="tab" data-toggle="tab" class="nav-link" title="" aria-selected="false" style="color:#4F4F4F; font-weight:400; font-size:16px;padding:11px 20px; border-top-left-radius:10px; border-top-right-radius:10px;"><span class="fa fa-question-circle" style="margin-right: 5px;"> </span> FAQs</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content shadow">
|
||||
<div class="tab-pane screen fade active show" id="dep3" role="tabpanel" aria-labelledby="dep3-tab">
|
||||
<section class="index-banner position-relative" style=" border-radius: 10px;">
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row text-center justify-content-center">
|
||||
<h3 style="font-size: 40px; margin-bottom: 24px; text-align: center;">Free 3 Months Support</h3>
|
||||
</div>
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<h3 style="font-size: 24px; margin-bottom: 24px; text-align: center;">Need help or any technical support ?</h3>
|
||||
<div class="d-flex align-items-start mb-4">
|
||||
<img src="etc/keyfeature.png" alt="Background image in Login page" class="img img-fluid" style="padding-right: 1.5rem;">
|
||||
<div>
|
||||
<p style="font-size:18px; line-height:24px;">Kanak Infosystem will provide free 3 months support for bug fixes, any doubts or queries, installation, configuration support or any types of issues related to this module.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-start mb-4">
|
||||
<img src="etc/keyfeature.png" alt="Background image in Login page" class="img img-fluid" style="padding-right: 1.5rem;">
|
||||
<div>
|
||||
<p style="font-size:18px; line-height:24px;">At our company, we take pride in providing exceptional help and technical support to our valued customers.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-start mb-4">
|
||||
<img src="etc/keyfeature.png" alt="Background image in Login page" class="img img-fluid" style="padding-right: 1.5rem;">
|
||||
<div>
|
||||
<p style="font-size:18px; line-height:24px;">Our team of dedicated experts is well-versed in the intricacies of the Odoo platform.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="support mt32">
|
||||
<a href="mailto:sales@kanakinfosystems.com">
|
||||
<span class="badge badge-pill badge-light" style="font-size: 18px;margin: 5px;color:#fff; background-color: #3674fc; border-radius:20px; padding: 10px 20px;min-width: 150px;">
|
||||
<span><i class="fa fa-envelope-o" style="font-size: 20px; font-weight: bold; margin-right: 5px;"></i>
|
||||
</span> Email Us
|
||||
</span>
|
||||
</a>
|
||||
<a href="skype:kanakinfosystems?chat">
|
||||
<span class="badge badge-pill badge-light" style="font-size: 18px;margin: 5px;color:#fff; background-color: #3674fc;border-radius:20px;padding: 10px 20px;min-width: 150px;">
|
||||
<span><i class="fa fa-skype" style="font-size: 20px; margin-right: 5px;"></i>
|
||||
</span> Skype
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<img src="etc/support.jpg" alt="Background image in Login page" class="img img-fluid">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="tab-pane screen fade" id="change_log" role="tabpanel">
|
||||
<section class="index-banner position-relative" style=" border-radius: 10px;">
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="d-flex align-items-center mb16" style="color:#22304f; font-size: 20px;">
|
||||
<i class="fa fa-calendar" style="margin-right: 10px;"></i>
|
||||
<span style="font-weight: bold; padding-right: 5px;">Version 17.0.1.0</span>
|
||||
<small>(20<sup>th</sup>November 2023)</small>
|
||||
</div>
|
||||
<div style="font-size: 16px;">
|
||||
<ul style="vertical-align:top; margin-left:8px">
|
||||
<li>Initial Release</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="tab-pane screen fade" id="dep5" role="tabpanel">
|
||||
<section class="index-banner position-relative" style=" border-radius: 10px;">
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<section class="s_faq">
|
||||
<div id="accordion" class="accordion" role="tablist" aria-multiselectable="true">
|
||||
<div class="card" style="border:1px solid #e5e5e5; margin-bottom: 20px;">
|
||||
<h5 class="card-header" style="border:0px; font-size: 18px;background-color: rgba(0, 0, 0, 0.03);" role="tab" id="heading_3">
|
||||
<a style="font-weight:600; color:#291a1a" role="button" class="collapsed" data-toggle="collapse" href="#F3" aria-expanded="false" aria-controls="F3">Is this app compatible with Odoo Enterprise?</a>
|
||||
</h5>
|
||||
<div id="F3" class="collapsed collapse" role="tabpanel" aria-labelledby="heading_3" aria-expanded="true" style="" data-parent="#accordion">
|
||||
<div class="card-body" style="border-top :1px solid #e5e5e5; padding: 20px;">
|
||||
<p class="mb0"> Yes, our app works with Odoo Enterprise as well as Community.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="border:1px solid #e5e5e5; margin-bottom: 20px;">
|
||||
<h5 class="card-header" style="border:0px; font-size: 18px;background-color: rgba(0, 0, 0, 0.03);" role="tab" id="heading_4">
|
||||
<a style="font-weight:600; color:#291a1a" role="button" class="collapsed" data-toggle="collapse" href="#F4" aria-expanded="false" aria-controls="F4">Is this app compatible with Windows or Ubuntu?</a>
|
||||
</h5>
|
||||
<div id="F4" class="collapse" role="tabpanel" aria-labelledby="heading_4" aria-expanded="false" data-parent="#accordion">
|
||||
<div class="card-body" style="border-top :1px solid #e5e5e5; padding: 20px;">
|
||||
<p class="mb0">
|
||||
Yes, our app works with Windows or Ubuntu operating system.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="border:1px solid #e5e5e5; margin-bottom: 20px;">
|
||||
<h5 class="card-header" style="border:0px; font-size: 18px;background-color: rgba(0, 0, 0, 0.03);" role="tab" id="heading_buyer_faq_06">
|
||||
<a style="font-weight:600; color:#291a1a" role="button" class="collapsed" data-toggle="collapse" href="#buyer_faq_06" aria-expanded="false" aria-controls="buyer_faq_06">Can i resell or distribute the Module?</a>
|
||||
</h5>
|
||||
<div id="buyer_faq_06" class="collapse" role="tabpanel" aria-labelledby="heading_buyer_faq_06" aria-expanded="false" data-parent="#accordion">
|
||||
<div class="card-body" style="border-top :1px solid #e5e5e5; padding: 20px;">
|
||||
<p class="mb0">No! You can not resell or distribute this module. This module can only used for your Odoo ERP System.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner shadow position-relative mt40" style="border-radius: 10px;">
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="align-items-center text-center" style="margin-bottom: 32px;">
|
||||
<h1 style="font-weight: bold; font-size: 35px;">Suggested Apps</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div id="suggested_apps" class="carousel slide" data-ride="carousel" data-interval="10000">
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/instagram_feed_snippet/" target="_blank">
|
||||
<div style="border-radius:10px">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/banner_instagram_feed_snippet.png">
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/odoo_inbox/" target="_blank">
|
||||
<div style="border-radius:10px; margin-top: 10px;">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/banner_odoo_inbox.gif">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/odoo_microsoft_azure_sso/" target="_blank">
|
||||
<div style="border-radius:10px">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/banner_odoo_microsoft_azure_sso.jpg">
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/knk_sale_return/" target="_blank">
|
||||
<div style="border-radius:10px; margin-top: 10px;">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/knk_sale_return.jpg">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/schedule_delivery_knk/" target="_blank">
|
||||
<div style="border-radius:10px">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/schedule_delivery_knk.jpg">
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/pos_prescription_knk/" target="_blank">
|
||||
<div style="border-radius:10px; margin-top: 10px;">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/banner_pos_prescription_knk.jpg">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item" style="min-height:0px">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/pizza_modifiers/" target="_blank">
|
||||
<div style="border-radius:10px">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/banner_pizza_modifiers.gif">
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/order_history/" target="_blank">
|
||||
<div style="border-radius:10px; margin-top: 10px;">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/order_history.jpg">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/pos_lot_selection_knk/" target="_blank">
|
||||
<div style="border-radius:10px">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/banner_pos_lot_selection_knk.gif">
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/send_direct_print_knk/" target="_blank">
|
||||
<div style="border-radius:10px; margin-top: 10px;">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/banner_send_direct_print_knk.jpg">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/job_portal_kanak/" target="_blank">
|
||||
<div style="border-radius:10px">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/banner_job_portal_kanak.gif">
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/sale_approval_kanak/" target="_blank">
|
||||
<div style="border-radius:10px; margin-top: 10px;">
|
||||
<img class="img img-fluid center-block" style="border-radius:10px;" src="apps/sale_approval_kanak.jpg">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Left and right controls -->
|
||||
<a class="carousel-control-prev" href="#suggested_apps" data-slide="prev" style="margin-left: -30pt;width:35px; color:#000; opacity: 1;">
|
||||
<span style="height: 35px; width: 35px; padding: 5px; background-color: #3c3b80; color: #fff; background-image: none;">
|
||||
<i class="fa fa-angle-double-left" style="font-size:24px"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="carousel-control-next" href="#suggested_apps" data-slide="next" style="margin-right: -30pt;width:35px; color:#000; opacity: 1;">
|
||||
<span style="height: 35px; width: 35px; padding: 5px; background-color: #3c3b80; color: #fff; background-image: none;">
|
||||
<i class="fa fa-angle-double-right" style="font-size:24px"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END OF RELATED PRODUCTS -->
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner shadow position-relative mt40" style="border-radius: 10px;">
|
||||
<img class="w-100 h-100 position-absolute img-fluid" src="etc/3-background.png" style="border-radius: 10px;" />
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="align-items-center text-center" style="margin-bottom: 32px;">
|
||||
<h1 class="mt-2" style="font-weight: bold; font-size: 35px; color: #fff;">Our Services</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="content text-center mb32">
|
||||
<img src="services/Hire-Odoo-Developer.png" class="img img-fluid mb16" style="">
|
||||
<p style="color: #fff; font-size: 20px; font-weight: bold; ">Hire Odoo Developer</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="content text-center mb32">
|
||||
<img src="services/Odoo-Customization.png" class="img img-fluid mb16" style="">
|
||||
<p style="color: #fff; font-size: 20px; font-weight: bold; ">Odoo Customization</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="content text-center mb32">
|
||||
<img src="services/Odoo-Development.png" class="img img-fluid mb16" style="">
|
||||
<p style="color: #fff; font-size: 20px; font-weight: bold; ">Odoo Development</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="content text-center mb32">
|
||||
<img src="services/Odoo-Installation.png" class="img img-fluid mb16" style="">
|
||||
<p style="color: #fff; font-size: 20px; font-weight: bold;">Odoo Installation</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="content text-center mb32">
|
||||
<img src="services/Odoo-Integration.png" class="img img-fluid mb16" style="">
|
||||
<p style="color: #fff; font-size: 20px; font-weight: bold;">Odoo Integration</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="content text-center mb32">
|
||||
<img src="services/Odoo-Resource.png" class="img img-fluid mb16" style="">
|
||||
<p style="color: #fff; font-size: 20px; font-weight: bold;">Odoo Resource</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="content text-center mb32">
|
||||
<img src="services/Odoo-Themes.png" class="img img-fluid mb16" style="">
|
||||
<p style="color: #fff; font-size: 20px; font-weight: bold;">Odoo Themes</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="content text-center mb32">
|
||||
<img src="services/Odoo-Training.png" class="img img-fluid mb16" style="">
|
||||
<p style="color: #fff; font-size: 20px; font-weight: bold;">Odoo Training</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="index-banner shadow-sm position-relative mt40" style="border-bottom:4px solid #cf6cb3; border-radius: 10px;">
|
||||
<img class="w-100 h-100 position-absolute img-fluid" src="notice_bg.jpg" style="border-radius: 10px;">
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row align-items-end">
|
||||
<div class="col-12" style="font-size: 18px;">
|
||||
<h1 style="text-align: center; font-size: 35px; margin-bottom: 32px; margin-top: 16px; color: red;">Important Notice</h1>
|
||||
<p style="text-align: justify;">
|
||||
All applications are developed within the default, up-to-date Odoo environment, and as such, we cannot guarantee flawless compatibility with third-party apps. While we strive to ensure smooth integration, any conflicts or issues that arise due to third-party applications will require additional support services, which can be provided at an extra cost. Kindly contact our support team for more information or to arrange paid support.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="index-banner shadow position-relative mt40" style="border-radius: 10px;">
|
||||
<div class="container p-md-5 p-4 position-relative">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-12">
|
||||
<div class="content">
|
||||
<div class="icon mb16 text-center">
|
||||
<span class="fa fa-map-marker" style="color:#ffffff; background-color:#3c3b80; padding:10px; border-radius:100%; border:5px solid #cfd6fb; font-size:40px;height: 70px;width: 70px;text-align: center;" />
|
||||
</div>
|
||||
<div class="content text-center">
|
||||
<h1 style="font-size: 35px;color: #3c3b80; margin-bottom: 10px; font-weight: 600;">Kanak infosystems LLP.</h1>
|
||||
<p style="font-size: 20px;color: #3c3b80;">Unit no.307, The landmark, Urjanagar 1, Kudasan, Gandhinagar, Gujarat - 382421, India</p>
|
||||
</div>
|
||||
<div class="buttons-knk text-center">
|
||||
<div class="icon text-center">
|
||||
<a href="mailto:sales@kanakinfosystems.com" style="color:#ffffff; background-color:#3c3b80; padding:2px; border-radius:100%; border:5px solid #cfd6fb; font-size:30px;height: 60px;width: 60px;text-align: center; display: inline-block;margin: 10px;">
|
||||
<span class="fa fa-envelope-o" />
|
||||
</a>
|
||||
<a href="skype:kanakinfosystems?chat" style="color:#ffffff; background-color:#3c3b80; padding:2px; border-radius:100%; border:5px solid #cfd6fb; font-size:30px;height: 60px;width: 60px;text-align: center; display: inline-block;margin: 10px;">
|
||||
<span class="fa fa-skype" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 317 KiB |
|
After Width: | Height: | Size: 857 KiB |
|
After Width: | Height: | Size: 550 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="view_company_form" model="ir.ui.view">
|
||||
<field name="name">res.company.form.inherit.account</field>
|
||||
<field name="model">res.company</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='vat']" position="before">
|
||||
<field name="bg_image" widget="image"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<template id="custom_bg_image" name="Frontend Layout Image" inherit_id="web.frontend_layout">
|
||||
<xpath expr="//div[@id='wrapwrap']" position="attributes">
|
||||
<attribute name="t-attf-style">#{"background: transparent url('/dashboard') no-repeat scroll center center / cover;" if response_template == 'web.login' or 'auth_signup.signup' else ''}</attribute>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
|
@ -8,18 +8,22 @@
|
|||
'version': '1.1',
|
||||
'summary': 'Changes of the form',
|
||||
'description': "This module contains the changes in the job portal, candidates, appliant form",
|
||||
'depends': ['hr_recruitment_extended', 'website_hr_recruitment','website_hr_recruitment_extended','survey','hr_recruitment'],
|
||||
'depends': ['hr_recruitment_extended', 'website_hr_recruitment','website_hr_recruitment_extended','survey','hr_recruitment','web'],
|
||||
'data': [
|
||||
'data/mail_template_data.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/hr_applicant_form.xml',
|
||||
'views/hr_candidate_form.xml',
|
||||
'views/job_portal_changes.xml',
|
||||
'views/web_page_login.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend': {
|
||||
'web_portal_form_custom/static/src/css/candidate_card.css'
|
||||
},
|
||||
'web.assets_frontend': {
|
||||
'web_portal_form_custom/static/src/css/web_page.css'
|
||||
}
|
||||
},
|
||||
'post_init_hook': 'post_init_remove_duplicate_skills',
|
||||
'installable': True,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
.oe_login_form{
|
||||
background:rgba(255,255,255,.15);
|
||||
backdrop-filter:blur(18px);
|
||||
-webkit-backdrop-filter:blur(18px);
|
||||
|
||||
border:1px solid rgba(255,255,255,.25);
|
||||
border-radius:20px;
|
||||
box-shadow:0 15px 40px rgba(0,0,0,.25);
|
||||
}
|
||||
|
||||
.srivyn_brand_footer{
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 20px;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.srivyn_brand_footer strong{
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<odoo>
|
||||
<template id="web_login_inherit" inherit_id="web.login">
|
||||
|
||||
<!-- Increase login form width -->
|
||||
<xpath expr="//form" position="attributes">
|
||||
<attribute name="style">max-width:250px;margin:auto;padding-top:70px;;</attribute>
|
||||
</xpath>
|
||||
|
||||
<!-- <!– Company Logo –>-->
|
||||
<!-- <xpath expr="//form" position="before">-->
|
||||
<!-- <div class="text-center mb-4">-->
|
||||
<!-- <img src="/web_portal_form_custom/static/src/img/Copilot_20260529_143430-removebg-preview.png"-->
|
||||
<!-- alt="SRIVYN"-->
|
||||
<!-- style="max-height:90px;"/>-->
|
||||
<!-- </div>-->
|
||||
<!-- </xpath>-->
|
||||
|
||||
<!-- Footer -->
|
||||
<!-- <xpath expr="//select[@name='master_select']" position="after">-->
|
||||
<!-- <div class="text-center mt-3">-->
|
||||
<!-- <small class="text-muted">-->
|
||||
<!-- Powered by-->
|
||||
<!-- <strong>SRIVYN PLATFORMS</strong>-->
|
||||
<!-- </small>-->
|
||||
<!-- </div>-->
|
||||
<!-- </xpath>-->
|
||||
|
||||
</template>
|
||||
<odoo>
|
||||
<template id="brand_promotion_inherit"
|
||||
inherit_id="web.brand_promotion">
|
||||
|
||||
<xpath expr="//div[@class='o_brand_promotion']" position="replace">
|
||||
<div class="o_brand_promotion srivyn_brand_footer">
|
||||
Powered by <strong>SRIVYN PLATFORMS PVT.LTD</strong>
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
</odoo>
|
||||
</odoo>
|
||||