diff --git a/yuthon_holiday/i18n/zh_CN.po b/yuthon_holiday/i18n/zh_CN.po index 8831bcbb6..70be46235 100644 --- a/yuthon_holiday/i18n/zh_CN.po +++ b/yuthon_holiday/i18n/zh_CN.po @@ -62,3 +62,18 @@ msgstr "日" #: model_terms:ir.ui.view,arch_db:yuthon_holiday.hr_accrual_plan_view_form_inherit msgid "number of holiday days:" msgstr "假期天数:" + + + +#. module: hr_holidays +#. odoo-python +#: code:addons/hr_holidays/models/hr_leave.py:0 +#, python-format +msgid "" +"You've already booked time off which overlaps with this period:\n" +"%s\n" +"Attempting to double-book your time off won't magically make your vacation 2x better!\n" +msgstr "" +"您已有:\n" +"「%s」\n" +"的假期申请待审批,请勿重复提交。如需调整,请先联系审批人或撤回原申请。\n" diff --git a/yuthon_holiday/models/inherit_hr_leave.py b/yuthon_holiday/models/inherit_hr_leave.py index 0062274f2..fa40676b1 100644 --- a/yuthon_holiday/models/inherit_hr_leave.py +++ b/yuthon_holiday/models/inherit_hr_leave.py @@ -5,11 +5,13 @@ from email.policy import default from odoo import models, fields, api, _ from odoo.exceptions import ValidationError import re +from odoo.tools.misc import format_date class HrLeave(models.Model): _inherit = 'hr.leave' + @api.model def default_get(self, fields_list): default = super().default_get(fields_list) @@ -59,60 +61,120 @@ class HrLeave(models.Model): column2='attachment_id' ) request_hour_from = fields.Selection([ - ('0', '00:00 上午'), ('0.5', '00:30 上午'), - ('1', '1:00 上午'), ('1.5', '1:30 上午'), - ('2', '2:00 上午'), ('2.5', '2:30 上午'), - ('3', '3:00 上午'), ('3.5', '3:30 上午'), - ('4', '4:00 上午'), ('4.5', '4:30 上午'), - ('5', '5:00 上午'), ('5.5', '5:30 上午'), - ('6', '6:00 上午'), ('6.5', '6:30 上午'), - ('7', '7:00 上午'), ('7.5', '7:30 上午'), - ('8', '8:00 上午'), ('8.5', '8:30 上午'), - ('9', '9:00 上午'), ('9.5', '9:30 上午'), - ('10', '10:00 上午'), ('10.5', '10:30 上午'), - ('11', '11:00 上午'), ('11.5', '11:30 上午'), - ('12', '12:00 下午'), ('12.5', '12:30 下午'), - ('13', '1:00 下午'), ('13.5', '1:30 下午'), - ('14', '2:00 下午'), ('14.5', '2:30 下午'), - ('15', '3:00 下午'), ('15.5', '3:30 下午'), - ('16', '4:00 下午'), ('16.5', '4:30 下午'), - ('17', '5:00 下午'), ('17.5', '5:30 下午'), - ('18', '6:00 下午'), ('18.5', '6:30 下午'), - ('19', '7:00 下午'), ('19.5', '7:30 下午'), - ('20', '8:00 下午'), ('20.5', '8:30 下午'), - ('21', '9:00 下午'), ('21.5', '9:30 下午'), - ('22', '10:00 下午'), ('22.5', '10:30 下午'), - ('23', '11:00 下午'), ('23.5', '11:30 下午')], string='开始时间') + ('0', '00:00'), ('0.5', '00:30'), + ('1', '1:00'), ('1.5', '1:30'), + ('2', '2:00'), ('2.5', '2:30'), + ('3', '3:00'), ('3.5', '3:30'), + ('4', '4:00'), ('4.5', '4:30'), + ('5', '5:00'), ('5.5', '5:30'), + ('6', '6:00'), ('6.5', '6:30'), + ('7', '7:00'), ('7.5', '7:30'), + ('8', '8:00'), ('8.5', '8:30'), + ('9', '9:00'), ('9.5', '9:30'), + ('10', '10:00'), ('10.5', '10:30'), + ('11', '11:00'), ('11.5', '11:30'), + ('12', '12:00'), ('12.5', '12:30'), + ('13', '13:00'), ('13.5', '13:30'), + ('14', '14:00'), ('14.5', '14:30'), + ('15', '15:00'), ('15.5', '15:30'), + ('16', '16:00'), ('16.5', '16:30'), + ('17', '17:00'), ('17.5', '17:30'), + ('18', '18:00'), ('18.5', '18:30'), + ('19', '19:00'), ('19.5', '19:30'), + ('20', '20:00'), ('20.5', '20:30'), + ('21', '21:00'), ('21.5', '21:30'), + ('22', '22:00'), ('22.5', '22:30'), + ('23', '23:00'), ('23.5', '23:30')], string='开始时间') + request_hour_to = fields.Selection([ - ('0', '00:00 上午'), ('0.5', '00:30 上午'), - ('1', '1:00 上午'), ('1.5', '1:30 上午'), - ('2', '2:00 上午'), ('2.5', '2:30 上午'), - ('3', '3:00 上午'), ('3.5', '3:30 上午'), - ('4', '4:00 上午'), ('4.5', '4:30 上午'), - ('5', '5:00 上午'), ('5.5', '5:30 上午'), - ('6', '6:00 上午'), ('6.5', '6:30 上午'), - ('7', '7:00 上午'), ('7.5', '7:30 上午'), - ('8', '8:00 上午'), ('8.5', '8:30 上午'), - ('9', '9:00 上午'), ('9.5', '9:30 上午'), - ('10', '10:00 上午'), ('10.5', '10:30 上午'), - ('11', '11:00 上午'), ('11.5', '11:30 上午'), - ('12', '12:00 下午'), ('12.5', '12:30 下午'), - ('13', '1:00 下午'), ('13.5', '1:30 下午'), - ('14', '2:00 下午'), ('14.5', '2:30 下午'), - ('15', '3:00 下午'), ('15.5', '3:30 下午'), - ('16', '4:00 下午'), ('16.5', '4:30 下午'), - ('17', '5:00 下午'), ('17.5', '5:30 下午'), - ('18', '6:00 下午'), ('18.5', '6:30 下午'), - ('19', '7:00 下午'), ('19.5', '7:30 下午'), - ('20', '8:00 下午'), ('20.5', '8:30 下午'), - ('21', '9:00 下午'), ('21.5', '9:30 下午'), - ('22', '10:00 下午'), ('22.5', '10:30 下午'), - ('23', '11:00 下午'), ('23.5', '11:30 下午')], string='结束时间') + ('0', '12:00'), ('0.5', '12:30'), + ('1', '1:00'), ('1.5', '1:30'), + ('2', '2:00'), ('2.5', '2:30'), + ('3', '3:00'), ('3.5', '3:30'), + ('4', '4:00'), ('4.5', '4:30'), + ('5', '5:00'), ('5.5', '5:30'), + ('6', '6:00'), ('6.5', '6:30'), + ('7', '7:00'), ('7.5', '7:30'), + ('8', '8:00'), ('8.5', '8:30'), + ('9', '9:00'), ('9.5', '9:30'), + ('10', '10:00'), ('10.5', '10:30'), + ('11', '11:00'), ('11.5', '11:30'), + ('12', '12:00'), ('12.5', '12:30'), + ('13', '13:00'), ('13.5', '13:30'), + ('14', '14:00'), ('14.5', '14:30'), + ('15', '15:00'), ('15.5', '15:30'), + ('16', '16:00'), ('16.5', '16:30'), + ('17', '17:00'), ('17.5', '17:30'), + ('18', '18:00'), ('18.5', '18:30'), + ('19', '19:00'), ('19.5', '19:30'), + ('20', '20:00'), ('20.5', '20:30'), + ('21', '21:00'), ('21.5', '21:30'), + ('22', '22:00'), ('22.5', '22:30'), + ('23', '23:00'), ('23.5', '23:30')], string='结束时间') def _compute_request_unit_hours(self): if not self.env.context.get('no_change_request_unit_hours'): super()._compute_request_unit_hours() + @api.constrains('date_from', 'date_to', 'employee_id') + def _check_date(self): + + if self.env.context.get('leave_skip_date_check', False): + return + + all_employees = self.all_employee_ids + all_leaves = self.search([ + ('date_from', '<', max(self.mapped('date_to'))), + ('date_to', '>', min(self.mapped('date_from'))), + ('employee_id', 'in', all_employees.ids), + ('id', 'not in', self.ids), + ('state', 'not in', ['cancel', 'refuse']), + ]) + for holiday in self: + domain = [ + ('date_from', '<', holiday.date_to), + ('date_to', '>', holiday.date_from), + ('id', '!=', holiday.id), + ('state', 'not in', ['cancel', 'refuse']), + ] + + employee_ids = (holiday.employee_id | holiday.employee_ids).ids + search_domain = domain + [('employee_id', 'in', employee_ids)] + conflicting_holidays = all_leaves.filtered_domain(search_domain) + + if conflicting_holidays: + conflicting_holidays_list = [] + # Do not display the name of the employee if the conflicting holidays have an employee_id.user_id equivalent to the user id + holidays_only_have_uid = bool(holiday.employee_id) + holiday_states = dict(conflicting_holidays.fields_get(allfields=['state'])['state']['selection']) + for conflicting_holiday in conflicting_holidays: + conflicting_holiday_data = {} + conflicting_holiday_data['employee_name'] = conflicting_holiday.employee_id.name + conflicting_holiday_data['date_from'] = format_date(self.env, + min(conflicting_holiday.mapped('date_from'))) + conflicting_holiday_data['date_to'] = format_date(self.env, + min(conflicting_holiday.mapped('date_to'))) + conflicting_holiday_data['state'] = holiday_states[conflicting_holiday.state] + if conflicting_holiday.employee_id.user_id.id != self.env.uid: + holidays_only_have_uid = False + if conflicting_holiday_data not in conflicting_holidays_list: + conflicting_holidays_list.append(conflicting_holiday_data) + if not conflicting_holidays_list: + return + conflicting_holidays_strings = [] + if holidays_only_have_uid: + for conflicting_holiday_data in conflicting_holidays_list: + conflicting_holidays_string = _('%(date_from)s - %(date_to)s', + date_from=conflicting_holiday_data['date_from'], + date_to=conflicting_holiday_data['date_to']) + conflicting_holidays_strings.append(conflicting_holidays_string) + raise ValidationError(_("""\ + 您已有:「%s」 的假期申请待审批,请勿重复提交。如需调整,请先联系审批人或撤回原申请。 + """, + "\n".join(conflicting_holidays_strings))) + + super()._check_date() + class HolidaysRequestBatch(models.Model): _name = 'hr.leave.batch' _description = '请假审批' diff --git a/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py b/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py index 6a365a312..39142b909 100644 --- a/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py +++ b/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py @@ -467,7 +467,7 @@ class HrAttendanceDetail(models.Model): min_time = min(checkin_time_list) # 查询最早时间上班时间 查询最晚下班时间 # 判断时间 在10分钟内说明是 异常 - if will_datetime_start + timedelta(minutes=10) > min_time > will_datetime_start: + if will_datetime_start + timedelta(minutes=10) > min_time > will_datetime_start + timedelta(minutes=1): attendance_obj.sudo().write({ "sch_check_in_time": will_datetime_start, "check_in": min_time, @@ -476,7 +476,7 @@ class HrAttendanceDetail(models.Model): "is_abnormal": True, "absenteeism_card": False, }) - elif will_datetime_start + timedelta(hours=1) > min_time > will_datetime_start: + elif will_datetime_start + timedelta(hours=1) > min_time > will_datetime_start + timedelta(minutes=1): attendance_obj.sudo().write({ "sch_check_in_time": will_datetime_start, "check_in": min_time, @@ -485,7 +485,7 @@ class HrAttendanceDetail(models.Model): "is_abnormal": False, "absenteeism_card": False, }) - elif min_time > will_datetime_start + timedelta(hours=1) and min_time > will_datetime_start: + elif min_time > will_datetime_start + timedelta(hours=1) and min_time > will_datetime_start + timedelta(minutes=1): attendance_obj.sudo().write({ "sch_check_in_time": will_datetime_start, "check_in": min_time, @@ -553,7 +553,7 @@ class HrAttendanceDetail(models.Model): max_time = max(checkin_time_list) # 如果上班没有打卡 if not attendance_obj.check_in: - if will_datetime_start + timedelta(minutes=10) > max_time > will_datetime_start: + if will_datetime_start + timedelta(minutes=10) > max_time > will_datetime_start + timedelta(minutes=1): attendance_obj.sudo().write({ "sch_check_in_time": will_datetime_start, "check_in": max_time, @@ -562,7 +562,7 @@ class HrAttendanceDetail(models.Model): "is_abnormal": True, "absenteeism_card": True, }) - elif will_datetime_start + timedelta(hours=1) > max_time > will_datetime_start: + elif will_datetime_start + timedelta(hours=1) > max_time > will_datetime_start + timedelta(minutes=1): attendance_obj.sudo().write({ "sch_check_in_time": will_datetime_start, "check_in": max_time, @@ -571,7 +571,7 @@ class HrAttendanceDetail(models.Model): "is_abnormal": True, "absenteeism_card": True, }) - elif max_time > will_datetime_start + timedelta(hours=1) and max_time > will_datetime_start: + elif max_time > will_datetime_start + timedelta(hours=1) and max_time > will_datetime_start + timedelta(minutes=1): attendance_obj.sudo().write({ "sch_check_in_time": will_datetime_start, "check_in": max_time, @@ -594,7 +594,7 @@ class HrAttendanceDetail(models.Model): elif attendance_obj.check_in >= max_time: attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True, "absenteeism_card": True}) else: - if will_datetime_end - timedelta(minutes=10) < max_time < will_datetime_end: + if will_datetime_end - timedelta(minutes=10) < max_time < will_datetime_end - timedelta(minutes=1): attendance_obj.sudo().write({ "sch_check_out_time": will_datetime_end, "check_out": max_time, @@ -603,7 +603,7 @@ class HrAttendanceDetail(models.Model): "is_abnormal": True, # "absenteeism_card": False, }) - elif will_datetime_end - timedelta(hours=1) < max_time < will_datetime_end: + elif will_datetime_end - timedelta(hours=1) < max_time < will_datetime_end - timedelta(minutes=1): attendance_obj.sudo().write({ "sch_check_out_time": will_datetime_end, "check_out": max_time, diff --git a/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py b/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py index 28d42f7df..a3debf01a 100644 --- a/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py +++ b/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py @@ -26,7 +26,7 @@ class YuthonOnboardApproval(models.Model): employee_name = fields.Char(string='姓名') users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id) department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门") - yuthon_company = fields.Selection([('thtz', '天河投资集团'), ('thwg', '天河物管'), + yuthon_company = fields.Selection([('thtz', '天河投资集团'), ('thwg', '天河物管'), ('ttcj','天投城建'), ('thlc', '天河粮储')], string="甲方") account = fields.Char(string='账号') reason = fields.Html(string="正文") diff --git a/yuthon_property/models/property_bank_statements.py b/yuthon_property/models/property_bank_statements.py index 243c07292..aeb3f3da8 100644 --- a/yuthon_property/models/property_bank_statements.py +++ b/yuthon_property/models/property_bank_statements.py @@ -17,14 +17,31 @@ class PropertyBankStatements(models.Model): original_amount = fields.Float(string='交易金额') voucher_type = fields.Selection([('electronic_transfer', '电子转账凭证'), ('telegraphic_transfer', '电汇凭证')], string='凭证种类') remake = fields.Text('备注') - property_id = fields.Many2one('yuthon.property', string='物业地址') - + property_ids = fields.Many2many('yuthon.property', string='物业地址') def button_reconciliation(self): - pass + for rec in self: + for property_id in rec.property_ids: + receivable_ids = self.env['property.accounts.receivable'].search([('property_id', '=', property_id.id)]) + for receivable_id in receivable_ids: + difference_amount = receivable_id.original_amount - rec.original_amount + receivable_id.write({ + 'is_reconciliation': True, + 'difference_amount': difference_amount + }) def button_all_reconciliation(self): - pass + statements_ids = self.env["property.bank.statements"].browse( + self._context.get('active_ids', self._context.get('active_id'))) + for statements_id in statements_ids: + for property_id in statements_id.property_ids: + receivable_ids = self.env['property.accounts.receivable'].search([('property_id', '=', property_id.id)]) + for receivable_id in receivable_ids: + difference_amount = receivable_id.original_amount - statements_id.original_amount + receivable_id.write({ + 'is_reconciliation': True, + 'difference_amount': difference_amount + }) def unlink(self): return super().unlink() \ No newline at end of file diff --git a/yuthon_property/views/property_bank_statements_views.xml b/yuthon_property/views/property_bank_statements_views.xml index a8065d51a..0e3a1ebab 100644 --- a/yuthon_property/views/property_bank_statements_views.xml +++ b/yuthon_property/views/property_bank_statements_views.xml @@ -11,7 +11,7 @@ - + @@ -30,6 +30,6 @@ code - action = model.action_yuthon_salary_wizard() + action = model.button_all_reconciliation() \ No newline at end of file diff --git a/yuthon_property/wizard/property_statements_wizard.py b/yuthon_property/wizard/property_statements_wizard.py index f990cdd9b..961229812 100644 --- a/yuthon_property/wizard/property_statements_wizard.py +++ b/yuthon_property/wizard/property_statements_wizard.py @@ -27,33 +27,36 @@ class PropertyStatementsWizard(models.Model): self.property_bank_statements_data(row) def property_bank_statements_data(self, row): - if row[0].value: - start_time = pd.to_datetime(row[0].value, unit='d', origin='1899-12-30') + contract_ids = self.env['property.lease.contract'] + if row[2].value: + start_time = pd.to_datetime(row[2].value, unit='d', origin='1899-12-30') else: start_time = None + name = row[0].value company_id = self.env['yuthon.property.company'].search([('name', '=', row[1].value)]) - name = row[2].value - name_account = row[3].value - remake = row[4].value - original_amount = row[5].value - contract_id = self.env['property.lease.contract'].search([('name', '=', row[6].value)]) - property_id = self.env['yuthon.property'].search([('name', '=', row[7].value)]) - contract_account = row[8].value - contract_penalty = row[9].value - voucher_type = row[10].value + name_account = row[7].value + voucher_type = row[15].value voucher_type_dict = {'电子转账凭证': 'electronic_transfer', '电汇凭证': 'telegraphic_transfer'} voucher_type = voucher_type_dict.get(voucher_type) + property_ids = [] + if name: + bank_id = self.env['property.bank.line'].search([('bank', '=', name)]) + if bank_id: + tenant_id = bank_id.tenant_id + if tenant_id: + contract_ids = self.env['property.lease.contract'].search([('lessee_id', '=', tenant_id.id)]) + for contract in contract_ids: + if contract.lease_ids: + lease_id = contract.lease_ids[0].address_id + if lease_id: + property_ids.append(lease_id.id) bank_data = { - 'name':name, - 'start_time':start_time, + 'name': name, + 'contract_ids':[(6, 0, contract_ids.ids)] if contract_ids else [], + 'property_ids':[(6, 0, property_ids)], 'company_id': company_id.id, + 'start_time': start_time, 'name_account': name_account, - 'remake': remake, - 'original_amount': original_amount, - 'contract_id': contract_id.id, - 'property_id': property_id.id, - 'contract_account': contract_account, - 'contract_penalty': contract_penalty, 'voucher_type': voucher_type } self.env['property.bank.statements'].create(bank_data) diff --git a/yuthon_property_approval/models/inherit_yuthon_property.py b/yuthon_property_approval/models/inherit_yuthon_property.py index 6169493a2..f1b7fe820 100644 --- a/yuthon_property_approval/models/inherit_yuthon_property.py +++ b/yuthon_property_approval/models/inherit_yuthon_property.py @@ -14,7 +14,8 @@ class YuthonProperty(models.Model): class PropertyBankStatements(models.Model): _inherit = 'property.bank.statements' - contract_id = fields.Many2one('property.lease.contract', string="关联租赁合同审批") + contract_id = fields.Many2one('property.lease.contract', string="关联租赁合同审批") + contract_ids = fields.Many2many('property.lease.contract', string="租赁合同审批") def button_manage(self): pass diff --git a/yuthon_property_approval/views/inherit_yuthon_property_views.xml b/yuthon_property_approval/views/inherit_yuthon_property_views.xml index 01ccb8e84..e5242786d 100644 --- a/yuthon_property_approval/views/inherit_yuthon_property_views.xml +++ b/yuthon_property_approval/views/inherit_yuthon_property_views.xml @@ -331,11 +331,11 @@ property.bank.statements - - + + -