diff --git a/.github/workflows/production_pull_code.yml b/.github/workflows/production_pull_code.yml index 6254be019..3aa0018b1 100644 --- a/.github/workflows/production_pull_code.yml +++ b/.github/workflows/production_pull_code.yml @@ -8,27 +8,28 @@ on: required: true type: choice options: - - Cyber-Security-Project + # - Cyber-Security-Project - Ensan-Project - Helpdesk-Khabir-Project - King-AbdelAziz-Library-Project - Twahod-Project - Ekram-Project + - Sahli-Project jobs: # Cyber Project - cyber_master_server: - name: Deploy to Cyber Master - runs-on: cyber-client-project-runner - if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'Cyber-Security-Project' && (github.ref == 'refs/heads/master_odex-event' || github.ref == 'refs/heads/master_odex25_accounting' || github.ref == 'refs/heads/master_odex25_base' || github.ref == 'refs/heads/master_odex25_dms' || github.ref == 'refs/heads/master_odex25_fleet' || github.ref == 'refs/heads/master_odex25_ENSAN' || github.ref == 'refs/heads/master_odex25_hr' || github.ref == 'refs/heads/master_odex25_inventory' || github.ref == 'refs/heads/master_odex25_maintenance' || github.ref == 'refs/heads/master_odex25_mobile' || github.ref == 'refs/heads/master_odex25_pos' || github.ref == 'refs/heads/master_odex25_project' || github.ref == 'refs/heads/master_odex25_purchase' || github.ref == 'refs/heads/master_odex25_realstate' || github.ref == 'refs/heads/master_odex25_sales' || github.ref == 'refs/heads/master_odex25_survey' || github.ref == 'refs/heads/master_odex25_transactions' || github.ref == 'refs/heads/master_odex25_website' || github.ref == 'refs/heads/master_openeducat_erp-14.0.1.0' || github.ref == 'refs/heads/master_odex25_ensan') - steps: - - name: Checkout And Restart Project - run: | - echo "** [INFO] Running on branch --> ${GITHUB_REF#refs/heads/}" - mkdir -p ~/master_branch_sha - echo "$(date '+%Y-%m-%d %H:%M:%S') - ${{ github.sha }}" >> ~/master_branch_sha/${GITHUB_REF#refs/heads/} - sudo chmod +x ${{ secrets.CYBER_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh - sudo ${{ secrets.CYBER_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh ${{ secrets.CYBER_PROJECT_USER }} ${{ secrets.CYBER_STANDARD_FOLDER_PATH }} ${{ secrets.CYBER_MASTER_SERVICE }} master ${GITHUB_REF#refs/heads/master_} ${GITHUB_REF#refs/heads/} ${{ secrets.GH_TOKEN }} + # cyber_master_server: + # name: Deploy to Cyber Master + # runs-on: cyber-client-project-runner + # if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'Cyber-Security-Project' && (github.ref == 'refs/heads/master_odex-event' || github.ref == 'refs/heads/master_odex25_accounting' || github.ref == 'refs/heads/master_odex25_base' || github.ref == 'refs/heads/master_odex25_dms' || github.ref == 'refs/heads/master_odex25_fleet' || github.ref == 'refs/heads/master_odex25_ENSAN' || github.ref == 'refs/heads/master_odex25_hr' || github.ref == 'refs/heads/master_odex25_inventory' || github.ref == 'refs/heads/master_odex25_maintenance' || github.ref == 'refs/heads/master_odex25_mobile' || github.ref == 'refs/heads/master_odex25_pos' || github.ref == 'refs/heads/master_odex25_project' || github.ref == 'refs/heads/master_odex25_purchase' || github.ref == 'refs/heads/master_odex25_realstate' || github.ref == 'refs/heads/master_odex25_sales' || github.ref == 'refs/heads/master_odex25_survey' || github.ref == 'refs/heads/master_odex25_transactions' || github.ref == 'refs/heads/master_odex25_website' || github.ref == 'refs/heads/master_openeducat_erp-14.0.1.0' || github.ref == 'refs/heads/master_odex25_ensan') + # steps: + # - name: Checkout And Restart Project + # run: | + # echo "** [INFO] Running on branch --> ${GITHUB_REF#refs/heads/}" + # mkdir -p ~/master_branch_sha + # echo "$(date '+%Y-%m-%d %H:%M:%S') - ${{ github.sha }}" >> ~/master_branch_sha/${GITHUB_REF#refs/heads/} + # sudo chmod +x ${{ secrets.CYBER_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh + # sudo ${{ secrets.CYBER_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh ${{ secrets.CYBER_PROJECT_USER }} ${{ secrets.CYBER_STANDARD_FOLDER_PATH }} ${{ secrets.CYBER_MASTER_SERVICE }} master ${GITHUB_REF#refs/heads/master_} ${GITHUB_REF#refs/heads/} ${{ secrets.GH_TOKEN }} # Ensan Project ensan_master_server: @@ -101,4 +102,18 @@ jobs: sudo chmod +x ${{ secrets.EKRAM_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh sudo ${{ secrets.EKRAM_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh ${{ secrets.EKRAM_PROJECT_USER }} ${{ secrets.EKRAM_STANDARD_FOLDER_PATH }} ${{ secrets.EKRAM_MASTER_SERVICE }} master ${GITHUB_REF#refs/heads/master_} ${GITHUB_REF#refs/heads/} ${{ secrets.GH_TOKEN }} +# Sahli Prod project + sahli_prod_master_server: + name: Deploy to Sahli Prod Master + runs-on: sahli-client-project-runner + if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'Sahli-Project' && (github.ref == 'refs/heads/master_odex25_accounting' || github.ref == 'refs/heads/master_odex25_base' || github.ref == 'refs/heads/master_odex25_dms' || github.ref == 'refs/heads/master_odex25_hr' || github.ref == 'refs/heads/master_odex25_inventory' || github.ref == 'refs/heads/master_odex25_purchase' || github.ref == 'refs/heads/master_odex25_sales' || github.ref == 'refs/heads/master_odex25_project') + steps: + - name: Checkout And Restart Project + run: | + echo "** [INFO] Running on branch --> ${GITHUB_REF#refs/heads/}" + mkdir -p ~/master_branch_sha + echo "$(date '+%Y-%m-%d %H:%M:%S') - ${{ github.sha }}" >> ~/master_branch_sha/${GITHUB_REF#refs/heads/} + sudo chmod +x ${{ secrets.SAHLI_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh + sudo ${{ secrets.SAHLI_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh ${{ secrets.SAHLI_PROJECT_USER }} ${{ secrets.SAHLI_STANDARD_FOLDER_PATH }} ${{ secrets.SAHLI_PROD_MASTER_SERVICE }} master ${GITHUB_REF#refs/heads/master_} ${GITHUB_REF#refs/heads/} ${{ secrets.GH_TOKEN }} + diff --git a/odex25_hr/attendances/i18n/ar_001.po b/odex25_hr/attendances/i18n/ar_001.po index 83b332a19..5d447e121 100644 --- a/odex25_hr/attendances/i18n/ar_001.po +++ b/odex25_hr/attendances/i18n/ar_001.po @@ -185,6 +185,7 @@ msgstr "نسيان البصمة" msgid "Absent Report" msgstr "" + #. module: attendances #: model_terms:ir.ui.view,arch_db:attendances.resource_calendar_inherited_form msgid "Account Overtime" diff --git a/odex25_hr/attendances/models/hr_attendance_report.py b/odex25_hr/attendances/models/hr_attendance_report.py index 37364b7b3..019e85d72 100644 --- a/odex25_hr/attendances/models/hr_attendance_report.py +++ b/odex25_hr/attendances/models/hr_attendance_report.py @@ -237,7 +237,7 @@ class HrAttendanceReport(models.Model): 'delay': 0.0, 'leave': leaves, 'additional_hours': 0.0, - 'exists': 0.0, + 'exist_hours': 0.0, 'extra_break_duration': 0.0, 'absent': actual_absent_hours + missing_punch_hours + break_hours + early_exit_hours + lateness_hours , 'mission_by_days': total_mission, @@ -325,7 +325,7 @@ class HrAttendanceReport(models.Model): 'employee_name': attendance.employee_id.id, 'delay': lateness, 'leave': total_leaves, - 'exists': early_exist, + 'exist_hours': early_exist, 'extra_break_duration': extra_break_duration, 'absent': actual_absent_hours + missing_punch_hours + lateness + early_exist + extra_break_duration, 'mission_by_days': total_mission_by_day, @@ -358,7 +358,7 @@ class HrAttendanceReport(models.Model): temp_dict["leave"] = sum(item1["leave"] for item1 in grp2) temp_dict["mission_by_days"] = sum(item1["mission_by_days"] for item1 in grp14) temp_dict["absent"] = sum(item1["absent"] for item1 in grp3) - temp_dict["exists"] = sum(item1["exists"] for item1 in grp4) + temp_dict["exist_hours"] = sum(item1["exist_hours"] for item1 in grp4) temp_dict["extra_break_duration"] = sum(item1["extra_break_duration"] for item1 in grp5) temp_dict["absent_days_by_hr"] = sum(item1["absent_days_by_hr"] for item1 in grp6) temp_dict["total_hours"] = sum(item["total_hours"] for item in grp7) - ( @@ -418,7 +418,7 @@ class HrAttendanceReport(models.Model): 'delay': sum_line.delay + sum(sum_recs.mapped('line_ids.delay')), 'leave': sum_line.leave + sum(sum_recs.mapped('line_ids.leave')), 'absent': sum_line.absent + sum(sum_recs.mapped('line_ids.absent')), - 'exists': sum_line.exists + sum(sum_recs.mapped('line_ids.exists')), + 'exist_hours': sum_line.exists + sum(sum_recs.mapped('line_ids.exist_hours')), 'total_hours': sum_line.total_hours + sum(sum_recs.mapped('line_ids.total_hours')), 'dummy_field': sum_line.dummy_field + sum(sum_recs.mapped('line_ids.dummy_field')), 'total_deduction': sum_line.total_deduction + sum(sum_recs.mapped('line_ids.total_deduction')), diff --git a/odex25_hr/attendances/models/hr_attendance_report_line.py b/odex25_hr/attendances/models/hr_attendance_report_line.py index 62b7781c6..68f261613 100644 --- a/odex25_hr/attendances/models/hr_attendance_report_line.py +++ b/odex25_hr/attendances/models/hr_attendance_report_line.py @@ -8,7 +8,7 @@ class HrAttendanceReportLine(models.Model): employee_name = fields.Many2one(comodel_name='hr.employee') delay = fields.Float() leave = fields.Float(string='Holiday Hours') - exists = fields.Float() + exist_hours = fields.Float() extra_break_duration = fields.Float() absent = fields.Float(string='Absent Hours') mission_by_days = fields.Float(string='Mission Hours') diff --git a/odex25_hr/attendances/views/hr_attendance_report.xml b/odex25_hr/attendances/views/hr_attendance_report.xml index 50ea227d3..87d7cd3f7 100644 --- a/odex25_hr/attendances/views/hr_attendance_report.xml +++ b/odex25_hr/attendances/views/hr_attendance_report.xml @@ -66,7 +66,7 @@ - + @@ -88,7 +88,7 @@ - + diff --git a/odex25_hr/exp_official_mission/__manifest__.py b/odex25_hr/exp_official_mission/__manifest__.py index f28e5d335..a698ff8a5 100644 --- a/odex25_hr/exp_official_mission/__manifest__.py +++ b/odex25_hr/exp_official_mission/__manifest__.py @@ -25,6 +25,7 @@ 'views/ticket_view.xml', 'views/course_view.xml', 'views/appraisal_view.xml', + # 'views/res_partner_form_view.xml', 'views/training_menus.xml', 'wizard/employee_selection_wizard.xml', 'wizard/training_appraisal.xml', diff --git a/odex25_hr/exp_official_mission/i18n/ar_001.po b/odex25_hr/exp_official_mission/i18n/ar_001.po index c1baadb38..abe7212e7 100644 --- a/odex25_hr/exp_official_mission/i18n/ar_001.po +++ b/odex25_hr/exp_official_mission/i18n/ar_001.po @@ -2135,6 +2135,20 @@ msgstr "" msgid "name" msgstr "الاسم" +#. module: exp_official_mission +#: code:addons/exp_official_mission/models/hr_official_mission.py:0 +#: code:addons/exp_official_mission/models/hr_official_mission.py:0 +#: code:addons/exp_official_mission/models/hr_official_mission.py:0 +#: code:addons/exp_official_mission/models/hr_official_mission.py:0 +#, python-format +msgid "Company working calendar is not configured." +msgstr "لم يتم ضبط تقويم عمل الشركة." + +#. module: exp_official_mission +#: model:ir.model.fields,field_description:exp_official_mission.field_hr_official_mission_type__working_days +msgid "Working Days Only" +msgstr "أيام عمل فقط" + #. module: exp_official_mission #: code:addons/exp_official_mission/models/hr_official_mission.py:0 #: code:addons/exp_official_mission/models/hr_official_mission.py:0 @@ -2776,4 +2790,4 @@ msgstr "الموارد البشرية" #: model:ir.model.fields,field_description:exp_official_mission.field_hr_official_mission_type__analytic_account_id #: model_terms:ir.ui.view,arch_db:exp_official_mission.employee_official_mission_type_form_view msgid "Analytic Account" -msgstr "الحساب التحليلي" +msgstr "الحساب التحليلي" \ No newline at end of file diff --git a/odex25_hr/exp_official_mission/models/attendance.py b/odex25_hr/exp_official_mission/models/attendance.py index 4fd768659..a18eb4bb9 100644 --- a/odex25_hr/exp_official_mission/models/attendance.py +++ b/odex25_hr/exp_official_mission/models/attendance.py @@ -8,3 +8,10 @@ class AttendanceTransactions(models.Model): official_id = fields.Many2one('hr.official.mission', string='Mission Request') total_mission_hours = fields.Float() mission_name = fields.Many2one(related='official_id.mission_type', string='Mission Type', store=True) + + + +# class ResPartner(models.Model): +# _inherit = 'res.partner' +# +# training = fields.Boolean(string="Training",default=True) \ No newline at end of file diff --git a/odex25_hr/exp_official_mission/models/hr_official_mission.py b/odex25_hr/exp_official_mission/models/hr_official_mission.py index fda9e7628..79a4170f1 100644 --- a/odex25_hr/exp_official_mission/models/hr_official_mission.py +++ b/odex25_hr/exp_official_mission/models/hr_official_mission.py @@ -88,13 +88,14 @@ class HrOfficialMission(models.Model): employee_id = fields.Many2one('hr.employee', 'Responsible', default=lambda item: item.get_user_id(), domain=[('state', '=', 'open')]) - employee_no = fields.Char(related='employee_id.emp_no', readonly=True,string='Employee Number', store=True) + employee_no = fields.Char(related='employee_id.emp_no', readonly=True, string='Employee Number', store=True) reference = fields.Char(string="Reference Number") - company_id = fields.Many2one('res.company',string="Company", default=lambda self: self.env.user.company_id) + company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.user.company_id) ticket_request_id = fields.Many2one('hr.ticket.request', string="Ticket Request", readonly=True) - department_id2 = fields.Many2one(related='employee_id.department_id', readonly=True,store=True,string='Department') + department_id2 = fields.Many2one(related='employee_id.department_id', readonly=True, store=True, + string='Department') is_branch = fields.Many2one(related='department_id2.branch_name', store=True, readonly=True) attachment_count = fields.Integer(string="Attachments", compute="_compute_attachment_count") training_details = fields.Html('Training Details') @@ -102,6 +103,7 @@ class HrOfficialMission(models.Model): appraisal_count = fields.Integer(string="Appraisals", compute="get_employees_appraisal") hr_nomination = fields.Boolean(string="HR Nomination") + @api.onchange('hour_duration', 'date_duration') def compute_number_of_hours(self): for item in self: @@ -110,7 +112,8 @@ class HrOfficialMission(models.Model): - '''@api.constrains('employee_ids') + + @api.constrains('employee_ids') def chick_employee_ids(self): for item in self: if not item.employee_ids: @@ -138,16 +141,17 @@ class HrOfficialMission(models.Model): ######################################### def _compute_attachment_count(self): - attachment_data = self.env['ir.attachment'].read_group([('res_model', '=', 'hr.official.mission'), ('res_id', 'in', self.ids)], ['res_id'], ['res_id']) + attachment_data = self.env['ir.attachment'].read_group( + [('res_model', '=', 'hr.official.mission'), ('res_id', 'in', self.ids)], ['res_id'], ['res_id']) attachment = dict((data['res_id'], data['res_id_count']) for data in attachment_data) for rec in self: - rec.attachment_count = attachment.get(rec.id, 0)+sum(rec.employee_ids.mapped('attachment_count')) + rec.attachment_count = attachment.get(rec.id, 0) + sum(rec.employee_ids.mapped('attachment_count')) def action_get_attachment_view(self): res = self.env['ir.actions.act_window']._for_xml_id('base.action_attachment') related_ids = self.ids + self.employee_ids.ids related_models = ['hr.official.mission', 'hr.official.mission.employee'] - res['domain'] = [('res_model', 'in', related_models) ,('res_id', 'in', related_ids)] + res['domain'] = [('res_model', 'in', related_models), ('res_id', 'in', related_ids)] res['context'] = { 'default_res_model': 'hr.official.mission', 'default_res_id': self.id, @@ -169,7 +173,6 @@ class HrOfficialMission(models.Model): else: ctx['default_official_mission_id'] = self.id - ctx['default_employee_id'] = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1) return { @@ -202,7 +205,6 @@ class HrOfficialMission(models.Model): [('employee_id', 'in', employee_ids.ids), ('mission_id', '=', rec.id)]) rec.appraisal_count = len(training) - def action_employees_appraisal(self): employee_ids = self.employee_ids.mapped('employee_id') training = self.env['hr.employee.appraisal'].search( @@ -218,14 +220,12 @@ class HrOfficialMission(models.Model): 'context': {} } - def check_appraisal(self): - if all(record.appraisal_id for record in self.employee_ids): + if all(record.appraisal_id for record in self.employee_ids): self.appraisal_found = True else: self.appraisal_found = False - def get_user_id(self): employee_id = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1) if employee_id: @@ -261,7 +261,8 @@ class HrOfficialMission(models.Model): raise exceptions.Warning( _('Employee %s, The course does not follow the career record') % emp.employee_id.name) - @api.onchange('date_from', 'date_to', 'hour_to', 'hour_from', 'mission_type', 'state','table_ids') + + @api.onchange('date_from', 'date_to', 'hour_to', 'hour_from', 'mission_type','mission_type.working_days', 'state','table_ids') def _get_mission_no(self): for item in self: @@ -275,12 +276,30 @@ class HrOfficialMission(models.Model): end_mission_date = datetime.strptime(str(item.date_to), "%Y-%m-%d") if end_mission_date >= start_mission_date: + if not item.table_ids: days = (end_mission_date - start_mission_date).days item.date_duration = days + 1 else: unique_dates = set(item.table_ids.mapped('date')) item.date_duration = len(unique_dates) + + # days = (end_mission_date - start_mission_date).days + # item.date_duration = days + 1 + date_range = [start_mission_date.date() + timedelta(days=i) + for i in range((end_mission_date - start_mission_date).days + 1)] + + if item.mission_type.working_days: + calendar = item.company_id.resource_calendar_id + if not calendar: + raise ValidationError(_('Company working calendar is not configured.')) + + weekend_days = calendar.full_day_off or calendar.shift_day_off + weekend_names = [d.name.lower() for d in weekend_days] + date_range = [d for d in date_range if d.strftime('%A').lower() not in weekend_names] + + item.date_duration = len(date_range) + else: # item.duration = 0.0 raise exceptions.Warning(_('Date Form Must Be Less than Date To')) @@ -300,7 +319,7 @@ class HrOfficialMission(models.Model): if item.hour_to > item.hour_from: item.hour_duration = (item.hour_to - item.hour_from) else: - item.hour_duration = (24 -item.hour_from ) + item.hour_to + item.hour_duration = (24 - item.hour_from) + item.hour_to # raise exceptions.Warning(_('Hour to must be greater than hour from.')) if item.mission_type.maximum_hours > 0.0: @@ -325,8 +344,22 @@ class HrOfficialMission(models.Model): raise exceptions.Warning(_('date form must be less than date to')) else: - dayss = (leave_to - leave_from).days - line.days = dayss + 1 + # dayss = (leave_to - leave_from).days + # line.days = dayss + 1 + date_range = [leave_from.date() + timedelta(days=i) + for i in range((leave_to - leave_from).days + 1)] + + if item.mission_type.working_days: + calendar = item.company_id.resource_calendar_id + if not calendar: + raise ValidationError(_('Company working calendar is not configured.')) + + weekend_days = calendar.full_day_off or calendar.shift_day_off + weekend_names = [d.name.lower() for d in weekend_days] + date_range = [d for d in date_range if + d.strftime('%A').lower() not in weekend_names] + + line.days = len(date_range) if item.mission_type.related_with_financial is True: if item.mission_type.type_of_payment == 'fixed': if item.mission_type.day_price: @@ -338,7 +371,8 @@ class HrOfficialMission(models.Model): if item.mission_type.allowance_id: for rule in item.mission_type.allowance_id: if line.employee_id: - total += item.compute_rule(rule, line.sudo().employee_id.contract_id) + total += item.compute_rule(rule, + line.sudo().employee_id.contract_id) line.day_price = total line.amount = total * line.days @@ -439,14 +473,13 @@ class HrOfficialMission(models.Model): raise exceptions.Warning(_( 'You can not re-draft official mission because Appraisal with ID "%s" in not draft state ') % line.appraisal_id.employee_id.name) - item.state = 'draft' self.reset_emp_work_state() self.call_cron_function() def call_cron_function(self): transaction = self.env['hr.attendance.transaction'] - #if self.duration_type == 'days': + # if self.duration_type == 'days': if self.duration_type: if self.date_to and self.date_from: start_date = datetime.strptime(str(self.date_from), '%Y-%m-%d') @@ -457,12 +490,12 @@ class HrOfficialMission(models.Model): for i in range(delta.days + 1): day = start_date + timedelta(days=i) if today >= day.date(): - transaction.process_attendance_scheduler_queue(day, self.employee_ids.mapped( - 'employee_id')) - #else: - # day = datetime.strptime(str(self.date), '%Y-%m-%d') - #transaction.process_attendance_scheduler_queue(day, self.employee_ids.mapped( - # 'employee_id')) + transaction.process_attendance_scheduler_queue(day, self.employee_ids.mapped( + 'employee_id')) + # else: + # day = datetime.strptime(str(self.date), '%Y-%m-%d') + # transaction.process_attendance_scheduler_queue(day, self.employee_ids.mapped( + # 'employee_id')) def send(self): for item in self: @@ -483,7 +516,6 @@ class HrOfficialMission(models.Model): self.employee_ids.chick_not_overtime() self.state = "send" - def send_depart_manager(self): for item in self: if not item.employee_ids: @@ -499,7 +531,6 @@ class HrOfficialMission(models.Model): else: self.state = "send" - def direct_manager(self): # self.chick_employee_ids() self.employee_ids.chick_not_overtime() @@ -510,29 +541,29 @@ class HrOfficialMission(models.Model): manager = rec.sudo().employee_id.parent_id hr_manager = rec.sudo().employee_id.company_id.hr_manager_id if manager: - if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid: - rec.write({'state': 'depart_manager'}) - else: - raise exceptions.Warning( - _("Sorry, The Approval For The Direct Manager '%s' Only OR HR Manager!")%(manager.name)) + if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid: + rec.write({'state': 'depart_manager'}) + else: + raise exceptions.Warning( + _("Sorry, The Approval For The Direct Manager '%s' Only OR HR Manager!") % (manager.name)) else: rec.write({'state': 'depart_manager'}) if self.mission_type.approve_by == 'direct_manager': self.approve() - #Refuse For The Direct Manager Only + # Refuse For The Direct Manager Only def direct_manager_refused(self): for rec in self: manager = rec.sudo().employee_id.parent_id hr_manager = rec.sudo().employee_id.user_id.company_id.hr_manager_id if manager: if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid: - rec.refused() + rec.refused() else: - raise exceptions.Warning(_("Sorry, The Refuse For The Direct Manager '%s' Only OR HR Manager!") % (manager.name)) + raise exceptions.Warning( + _("Sorry, The Refuse For The Direct Manager '%s' Only OR HR Manager!") % (manager.name)) else: - rec.refused() - + rec.refused() def depart_manager(self): self.sudo().employee_ids.chick_not_overtime() @@ -542,13 +573,14 @@ class HrOfficialMission(models.Model): hr_manager = rec.sudo().employee_id.user_id.company_id.hr_manager_id if coach: if coach.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid: - rec.state = 'depart_manager' + rec.state = 'depart_manager' else: raise exceptions.Warning( _('Sorry, The Approval For The Department Manager %s Only OR HR Manager!') % (coach.name)) else: rec.state = 'depart_manager' - #Refuse For The Department Manager Only + + # Refuse For The Department Manager Only def dep_manager_refused(self): self.reset_emp_work_state() for rec in self: @@ -556,16 +588,17 @@ class HrOfficialMission(models.Model): hr_manager = rec.sudo().employee_id.user_id.company_id.hr_manager_id if coach: if coach.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid: - rec.refused() + rec.refused() else: - raise exceptions.Warning(_('Sorry, The Refuse For The Department Manager %s Only OR HR Manager') % (coach.name)) + raise exceptions.Warning( + _('Sorry, The Refuse For The Department Manager %s Only OR HR Manager') % (coach.name)) else: rec.refused() def hr_aaproval(self): # self.chick_employee_ids() - lines_draft_status = any(self.employee_ids.filtered(lambda emp: emp.status in ('draft','direct_manager'))) - if lines_draft_status and self.mission_type.work_state=='training': + lines_draft_status = any(self.employee_ids.filtered(lambda emp: emp.status in ('draft', 'direct_manager'))) + if lines_draft_status and self.mission_type.work_state == 'training': raise ValidationError(_("You must Approve all Employees Line First.")) self.employee_ids.chick_not_overtime() @@ -585,8 +618,8 @@ class HrOfficialMission(models.Model): if self.employee_ids and self.mission_type.related_with_financial: # move amounts to journal entries if self.move_type == 'accounting': - #if self.mission_type.account_id and self.mission_type.journal_id: - if self.mission_type.related_with_financial==True: + # if self.mission_type.account_id and self.mission_type.journal_id: + if self.mission_type.related_with_financial == True: for item in self.employee_ids: emp_type = item.employee_id.employee_type_id account_debit_id = self.mission_type.get_debit_mission_account_id(emp_type) @@ -596,15 +629,17 @@ class HrOfficialMission(models.Model): analytic_account_id = item.employee_id.department_id.analytic_account_id if not journal_id: - raise exceptions.Warning(_('You Must Enter The Journal Name Mission Type %s.')% self.mission_type.name) + raise exceptions.Warning( + _('You Must Enter The Journal Name Mission Type %s.') % self.mission_type.name) if not account_debit_id: - raise exceptions.Warning(_('Employee %s, The Mission %s Has No Account Setting Base On Employee Type.' - ) % (item.employee_id.name,self.mission_type.name)) + raise exceptions.Warning( + _('Employee %s, The Mission %s Has No Account Setting Base On Employee Type.' + ) % (item.employee_id.name, self.mission_type.name)) if item.amount > 0.0: debit_line_vals = { 'name': item.employee_id.name + ' in official mission "%s" ' % self.mission_type.name, 'debit': item.amount, - #'account_id': self.mission_type.account_id.id, + # 'account_id': self.mission_type.account_id.id, 'account_id': account_debit_id.id, 'partner_id': item.employee_id.user_id.partner_id.id, 'analytic_account_id': analytic_account_id.id, @@ -616,20 +651,20 @@ class HrOfficialMission(models.Model): 'partner_id': item.employee_id.user_id.partner_id.id } if not item.account_move_id: - move = self.env['account.move'].create({ - 'state': 'draft', - 'journal_id': journal_id.id, - 'date': date.today(), - 'ref': 'Official mission for employee "%s" ' % item.employee_id.name, - 'line_ids': [(0, 0, debit_line_vals), (0, 0, credit_line_vals)], - 'res_model': 'hr.official.mission', - 'res_id': self.id - }) - # fill account move for each employee - item.write({'account_move_id': move.id}) - #else: - #raise exceptions.Warning( - #_('You do not have account or journal in mission type "%s" ') % self.mission_type.name) + move = self.env['account.move'].create({ + 'state': 'draft', + 'journal_id': journal_id.id, + 'date': date.today(), + 'ref': 'Official mission for employee "%s" ' % item.employee_id.name, + 'line_ids': [(0, 0, debit_line_vals), (0, 0, credit_line_vals)], + 'res_model': 'hr.official.mission', + 'res_id': self.id + }) + # fill account move for each employee + item.write({'account_move_id': move.id}) + # else: + # raise exceptions.Warning( + # _('You do not have account or journal in mission type "%s" ') % self.mission_type.name) # move amounts to advantages of employee in contract elif self.move_type == 'payroll': @@ -988,7 +1023,7 @@ class HrOfficialMissionType(models.Model): max_amount = fields.Float('Maximum Amount') # relational fields - company_id = fields.Many2one('res.company',string="Company", default=lambda self: self.env.user.company_id) + company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.user.company_id) allowance_id = fields.Many2many('hr.salary.rule') journal_id = fields.Many2one('account.journal') account_id = fields.Many2one('account.account') @@ -1003,10 +1038,12 @@ class HrOfficialMissionType(models.Model): ('training', _('Training')), ('others', _('others'))], 'Work Status') special_hours = fields.Boolean(string='Special Hours', default=False) - approve_by = fields.Selection([('direct_manager', 'Direct Manager'), ('depart_manager', 'HR Department')], default='direct_manager', required=True) + approve_by = fields.Selection([('direct_manager', 'Direct Manager'), ('depart_manager', 'HR Department')], + default='direct_manager', required=True) transfer_by_emp_type = fields.Boolean('Transfer By Emp Type') account_ids = fields.One2many('hr.mission.type.account', 'mission_id') + working_days = fields.Boolean(string='Working Days Only', default=False) @api.onchange('duration_type') def _change_duration_type(self): @@ -1023,12 +1060,13 @@ class HrOfficialMissionType(models.Model): raise exceptions.Warning(_('You Can Not Delete Mission Type, Because There is a Related other record')) return super(HrOfficialMissionType, self).unlink() - #get acoount IDs base on Mission Type account config + # get acoount IDs base on Mission Type account config def get_debit_mission_account_id(self, emp_type): - if not self.transfer_by_emp_type : return self.account_id + if not self.transfer_by_emp_type: return self.account_id account_mapping = self.account_ids.filtered(lambda a: a.emp_type_id.id == emp_type.id) return account_mapping[0].debit_account_id if account_mapping else False + class HrMissionTypeAccount(models.Model): _name = 'hr.mission.type.account' _description = 'Mission Type Account Mapping' @@ -1038,7 +1076,6 @@ class HrMissionTypeAccount(models.Model): debit_account_id = fields.Many2one('account.account', string="Debit Account", required=True) - class HrOfficialMissionEmployee(models.Model): _name = 'hr.official.mission.employee' _rec_name = 'employee_id' @@ -1074,15 +1111,13 @@ class HrOfficialMissionEmployee(models.Model): store=True) attachment_count = fields.Integer(string="Attachments", compute="_compute_attachment_count") status = fields.Selection([('draft', _('Draft')), - ('direct_manager', _('Waiting Direct Manager')), - ('approved', _('Approved')), + ('direct_manager', _('Waiting Direct Manager')), + ('approved', _('Approved')), ('done', _('Done')), - ('refused', _('Refused')), - ], default="draft", tracking=True) + ('refused', _('Refused')), + ], default="draft", tracking=True) training_details = fields.Html('Training Details', related="official_mission_id.training_details") - - def approve(self): self.status = "approved" @@ -1095,15 +1130,13 @@ class HrOfficialMissionEmployee(models.Model): def set_to_draft(self): self.status = "draft" - def _compute_attachment_count(self): - attachment_data = self.env['ir.attachment'].read_group([('res_model', '=', 'hr.official.mission.employee'), ('res_id', 'in', self.ids)], ['res_id'], ['res_id']) + attachment_data = self.env['ir.attachment'].read_group( + [('res_model', '=', 'hr.official.mission.employee'), ('res_id', 'in', self.ids)], ['res_id'], ['res_id']) attachment = dict((data['res_id'], data['res_id_count']) for data in attachment_data) for rec in self: rec.attachment_count = attachment.get(rec.id, 0) - - def action_get_attachment_view(self): self.ensure_one() res = self.env['ir.actions.act_window']._for_xml_id('base.action_attachment') @@ -1111,8 +1144,6 @@ class HrOfficialMissionEmployee(models.Model): res['context'] = {'default_res_model': 'hr.official.mission.employee', 'default_res_id': self.id} return res - - @api.constrains('date_from', 'date_to', 'hour_from', 'hour_to', 'employee_id') def check_dates(self): for rec in self: @@ -1145,12 +1176,13 @@ class HrOfficialMissionEmployee(models.Model): ('official_mission_id.process_type', '=', 'training'), ('official_mission_id.course_name.id', '=', item.official_mission_id.course_name.id)]) if duplicated: - raise exceptions.ValidationError(_("Employee %s has already take this course.") % (item.employee_id.name)) + raise exceptions.ValidationError( + _("Employee %s has already take this course.") % (item.employee_id.name)) if item.official_mission_id and item.official_mission_id.mission_type.duration_type == 'days' \ and item.date_from and item.date_to: ### mission related_with_financial financial_missions = item.env['hr.official.mission.employee'].search( - [('official_mission_id.state', 'not in', ('draft','refuesd')), + [('official_mission_id.state', 'not in', ('draft', 'refuesd')), ('employee_id', '=', item.employee_id.id), ('official_mission_id.mission_type.related_with_financial', '=', True), ('official_mission_id.mission_type.duration_type', '=', 'days'), @@ -1158,19 +1190,22 @@ class HrOfficialMissionEmployee(models.Model): ]) days_per_year = item.official_mission_id.mission_type.max_days_year if days_per_year > 0.0: - if item.days > days_per_year: - raise exceptions.Warning(_('Sorry The Employee %s Cannot Exceed %s Days, This Maximum Days Per year.') % ( - item.employee_id.name,days_per_year)) + if item.days > days_per_year: + raise exceptions.Warning( + _('Sorry The Employee %s Cannot Exceed %s Days, This Maximum Days Per year.') % ( + item.employee_id.name, days_per_year)) if financial_missions: - if days_per_year > 0: - number_days = item.days - for rec in financial_missions: - year_last_record = datetime.strptime(str(rec.date_from), '%Y-%m-%d').year - year_now_record = datetime.strptime(str(item.date_from), '%Y-%m-%d').year - if year_last_record == year_now_record: - number_days = number_days + rec.days - if number_days > days_per_year: - raise exceptions.ValidationError(_("Sorry The Employee %s, The Number of Requests Cannot Exceed %s Maximum Days Per year.") % (rec.employee_id.name,days_per_year)) + if days_per_year > 0: + number_days = item.days + for rec in financial_missions: + year_last_record = datetime.strptime(str(rec.date_from), '%Y-%m-%d').year + year_now_record = datetime.strptime(str(item.date_from), '%Y-%m-%d').year + if year_last_record == year_now_record: + number_days = number_days + rec.days + if number_days > days_per_year: + raise exceptions.ValidationError( + _("Sorry The Employee %s, The Number of Requests Cannot Exceed %s Maximum Days Per year.") % ( + rec.employee_id.name, days_per_year)) #### prev_missions = item.env['hr.official.mission.employee'].search( @@ -1211,7 +1246,8 @@ class HrOfficialMissionEmployee(models.Model): raise exceptions.Warning( _('Sorry the maximum Amount allow for %s is %s and employee %s has Greater than ' 'Maximum Amount.') - % (item.official_mission_id.mission_type.name, item.official_mission_id.mission_type.max_amount, + % (item.official_mission_id.mission_type.name, + item.official_mission_id.mission_type.max_amount, item.employee_id.name)) Module = self.env['ir.module.module'].sudo() modules_permission = Module.search([('state', '=', 'installed'), ('name', '=', 'employee_requests')]) @@ -1222,7 +1258,8 @@ class HrOfficialMissionEmployee(models.Model): if date_to and date_from: delta = timedelta(days=1) while date_from <= date_to: - clause_1, clause_2, clause_3 = item.get_permission_domain(str(date_from), str(date_from)) + clause_1, clause_2, clause_3 = item.get_permission_domain(str(date_from), + str(date_from)) clause_final = [('employee_id', '=', item.employee_id.id), ('state', '!=', 'refused'), '|', '|'] + clause_1 + clause_2 + clause_3 permissions = self.env['hr.personal.permission'].search(clause_final) @@ -1300,7 +1337,19 @@ class HrOfficialMissionEmployee(models.Model): leave_to_1 = datetime.strptime(str(item.date_to), "%Y-%m-%d") leave_from_1 = datetime.strptime(str(item.date_from), "%Y-%m-%d") if leave_from_1 <= leave_to_1: - item.days = (leave_to_1 - leave_from_1).days + 1 + # item.days = (leave_to_1 - leave_from_1).days + 1 + date_range = [leave_from_1.date() + timedelta(days=i) + for i in range((leave_to_1 - leave_from_1).days + 1)] + if item.official_mission_id.mission_type and item.official_mission_id.mission_type.working_days: + calendar = item.official_mission_id.company_id.resource_calendar_id + if not calendar: + raise ValidationError(_('Company working calendar is not configured.')) + + weekend_days = calendar.full_day_off or calendar.shift_day_off + weekend_names = [d.name.lower() for d in weekend_days] + date_range = [d for d in date_range if d.strftime('%A').lower() not in weekend_names] + + item.days = len(date_range) else: raise exceptions.Warning(_('Date Form Must Be Less than Date To')) else: @@ -1309,7 +1358,19 @@ class HrOfficialMissionEmployee(models.Model): leave_to_1 = datetime.strptime(str(item.official_mission_id.date_to), "%Y-%m-%d") leave_from_1 = datetime.strptime(str(item.official_mission_id.date_from), "%Y-%m-%d") if leave_from_1 <= leave_to_1: - item.days = (leave_to_1 - leave_from_1).days + 1 + # item.days = (leave_to_1 - leave_from_1).days + 1 + date_range = [leave_from_1.date() + timedelta(days=i) + for i in range((leave_to_1 - leave_from_1).days + 1)] + if item.official_mission_id.mission_type and item.official_mission_id.mission_type.working_days: + calendar = item.official_mission_id.company_id.resource_calendar_id + if not calendar: + raise ValidationError(_('Company working calendar is not configured.')) + + weekend_days = calendar.full_day_off or calendar.shift_day_off + weekend_names = [d.name.lower() for d in weekend_days] + date_range = [d for d in date_range if d.strftime('%A').lower() not in weekend_names] + + item.days = len(date_range) else: raise exceptions.Warning(_('Date Form Must Be Less than Date To')) @@ -1322,7 +1383,7 @@ class HrOfficialMissionEmployee(models.Model): if item.official_mission_id.hour_to and item.official_mission_id.hour_from: if item.hour_from and item.hour_to: if (item.hour_to - item.hour_from) < 0: - item.hours = (24 -item.hour_from ) + item.hour_to + item.hours = (24 - item.hour_from) + item.hour_to item.total_hours = item.hours * item.days # raise exceptions.Warning(_('Number of hours to must be greater than hours from')) else: @@ -1332,7 +1393,7 @@ class HrOfficialMissionEmployee(models.Model): item.hour_from = item.official_mission_id.hour_from item.hour_to = item.official_mission_id.hour_to if (item.hour_to - item.hour_from) < 0: - item.hours = (24 -item.hour_from ) + item.hour_to + item.hours = (24 - item.hour_from) + item.hour_to item.total_hours = item.hours * item.days # raise exceptions.Warning(_('Number of hours to must be greater than hours from')) else: @@ -1487,7 +1548,7 @@ class HrOfficialMissionEmployee(models.Model): finacial = rec.official_mission_id.mission_type.related_with_financial delegation = rec.official_mission_id.mission_type.work_state if modules_req: - #if delegation == 'legation' and finacial: + # if delegation == 'legation' and finacial: if finacial == True: if rec.date_to and rec.date_from: clause_1 = ['&', ('employee_over_time_id.date_from', '<=', rec.date_from), @@ -1625,7 +1686,7 @@ class HrContract(models.Model): 'email_cc': '%s, %s' % (self.env.user.company_id.hr_email, rec.employee_id.work_email), 'model': self._name, } - #self.env['mail.mail'].create(main_content).send() + # self.env['mail.mail'].create(main_content).send() if emp in to_end.mapped('employee_id').ids: emp_to_end = to_end.filtered(lambda e: e.employee_id.id == emp) diff --git a/odex25_hr/exp_official_mission/views/hr_official_mission_type_view.xml b/odex25_hr/exp_official_mission/views/hr_official_mission_type_view.xml index 366a75a56..9afd12a6d 100644 --- a/odex25_hr/exp_official_mission/views/hr_official_mission_type_view.xml +++ b/odex25_hr/exp_official_mission/views/hr_official_mission_type_view.xml @@ -71,6 +71,7 @@ + - + attrs="{'readonly':[('state','not in',('draft','direct_manager','depart_manager','send'))] }" /> + + + attrs="{'readonly':[('state','not in',('draft','direct_manager','depart_manager','send'))] }" /> - + attrs="{'readonly':[('state','not in',('draft','direct_manager','depart_manager','send'))] }" /> + + attrs="{'required': [('state', '=', 'depart_manager')], + 'readonly':[('state','not in',('draft','direct_manager','depart_manager','send'))] }" /> - - + attrs="{'required': [('state', '=', 'depart_manager')], + 'readonly':[('state','not in',('draft','direct_manager','depart_manager','send'))] }" /> + + - + - - - - + attrs="{'readonly':[('state','!=','draft')]}" /> + + + + - + attrs="{'readonly':[('state','!=','draft')]}" /> + - - + + + attrs="{'readonly':[('state','!=','depart_manager')], 'required': [('state', '=', 'depart_manager')],'invisible':[('related_with_financial','=',False)]}" /> + 'required':[('move_type','=','payroll'),('state', '=', 'depart_manager'),('related_with_financial','=',True)]}" /> + + attrs="{'invisible':['|',('state','!=','approve'),('Tra_cost_invo_id','=',False)]}" + groups="hr_base.group_account_manager,hr.group_hr_user,hr_base.group_division_manager" /> - + - - - + + + - - -
-
+ +
+
+ attrs="{'readonly':[('state','not in',('depart_manager','direct_manager','send','draft'))]}"> - - - - + + + + - + - + + widget="float_time" /> + readonly="1" force_save="1" /> + attrs="{'column_invisible':[('parent.related_with_financial','=',False)]}" + readonly="0" /> - - + groups="hr_base.group_account_manager,hr.group_hr_user,hr_base.group_division_manager" /> + + - - - - - - - - + + + + - - - - + + + + - - - - + + + + -
+
- - - + + +
@@ -510,23 +580,26 @@ Employee Training Course hr.official.mission.employee - - - - - - - - - - - - - - - -
- + attrs="{'invisible':[('leave_type','=','annual')]}" /> + + attrs="{'invisible':[('visible_fields','!=',True)]}" /> -