GoodERP
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

401 lines
18KB

  1. # Copyright 2016 上海开阖软件有限公司 (http://www.osbzr.com)
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  3. from odoo import fields, models, api, _
  4. from datetime import datetime
  5. from odoo.exceptions import UserError
  6. class ResUsers(models.Model):
  7. _inherit = 'res.users'
  8. staff_ids = fields.One2many('staff', 'user_id', '关联员工')
  9. staff_id = fields.Many2one('staff', '公司员工',
  10. compute='_compute_staff_id',
  11. search='_search_company_staff',
  12. store=True,)
  13. staff_count = fields.Integer(compute='_compute_staff_count')
  14. @api.depends('staff_ids')
  15. def _compute_staff_id(self):
  16. for line in self:
  17. line.staff_id = False
  18. if line.staff_ids and len(line.staff_ids)==1:
  19. line.staff_id = line.staff_ids[0].id
  20. def _search_company_staff(self, operator, value):
  21. staff = self.env['staff'].search([
  22. ('name', operator, value),
  23. '|',
  24. ('company_id', '=', self.env.company.id),
  25. ('company_id', '=', False)
  26. ], order='company_id ASC')
  27. return [('id', 'in', staff.mapped('user_id').ids)]
  28. def action_create_staff(self):
  29. self.ensure_one()
  30. self.env['staff'].create(dict(
  31. name=self.name,
  32. company_id=self.env.company.id,
  33. **self.env['staff']._sync_user(self)
  34. ))
  35. @api.depends('staff_ids')
  36. def _compute_staff_count(self):
  37. for user in self.with_context(active_test=False):
  38. user.staff_count = len(user.staff_ids)
  39. class StaffDepartment(models.Model):
  40. _name = "staff.department"
  41. _description = '员工部门'
  42. _inherits = {'auxiliary.financing': 'auxiliary_id'}
  43. auxiliary_id = fields.Many2one(
  44. string='辅助核算',
  45. comodel_name='auxiliary.financing',
  46. ondelete='cascade',
  47. required=True,
  48. )
  49. dtype = fields.Selection(
  50. [("sell", "销售"), ("admin", "管理"), ("develop", "研发"), ("produce", "制造")],
  51. string='部门类别', default="admin", required=True)
  52. manager_id = fields.Many2one('staff', '部门经理')
  53. member_ids = fields.One2many('staff', 'department_id', '部门成员')
  54. parent_id = fields.Many2one('staff.department', '上级部门')
  55. child_ids = fields.One2many('staff.department', 'parent_id', '下级部门')
  56. jobs_ids = fields.One2many('staff.job', 'department_id', '职位')
  57. note = fields.Text('备注')
  58. active = fields.Boolean('启用', default=True)
  59. @api.constrains('parent_id')
  60. def _check_parent_id(self):
  61. '''上级部门不能选择自己和下级的部门'''
  62. for department in self:
  63. if department.parent_id:
  64. staffs = self.env['staff.department'].search(
  65. [('parent_id', '=', department.id)])
  66. if department.parent_id in staffs:
  67. raise UserError('上级部门不能选择他自己或者他的下级部门')
  68. def view_detail(self):
  69. for child_department in self:
  70. context = {'default_name': child_department.name,
  71. 'default_manager_id': child_department.manager_id.id,
  72. 'default_parent_id': child_department.parent_id.id}
  73. res_id = self.env['staff.department'].search(
  74. [('id', '=', child_department.id)])
  75. view_id = self.env.ref('staff.view_staff_department_form').id
  76. return {
  77. 'name': '部门/' + child_department.name,
  78. 'view_mode': 'form',
  79. 'res_model': 'staff.department',
  80. 'res_id': res_id.id,
  81. 'view_id': False,
  82. 'views': [(view_id, 'form')],
  83. 'type': 'ir.actions.act_window',
  84. 'context': context,
  85. 'target': 'current',
  86. }
  87. class StaffJob(models.Model):
  88. _name = "staff.job"
  89. _description = '员工职位'
  90. name = fields.Char('职位', required=True)
  91. note = fields.Text('描述')
  92. account_id = fields.Many2one('finance.account', '计提工资科目')
  93. department_id = fields.Many2one('staff.department', '部门')
  94. active = fields.Boolean('启用', default=True)
  95. company_id = fields.Many2one(
  96. 'res.company',
  97. string='公司',
  98. change_default=True,
  99. default=lambda self: self.env.company)
  100. _sql_constraints = [
  101. ('name_uniq', 'unique(name,department_id)', '同部门的职位不能重复!')
  102. ]
  103. class StaffEmployeeCategory(models.Model):
  104. _name = "staff.employee.category"
  105. _description = '员工层级'
  106. def _get_default_color(self):
  107. return randint(1, 11)
  108. name = fields.Char('名称',required=True)
  109. parent_id = fields.Many2one('staff.employee.category', '上级标签', index=True)
  110. chield_ids = fields.One2many(
  111. 'staff.employee.category', 'parent_id', '下级标签')
  112. employee_ids = fields.Many2many('staff',
  113. 'staff_employee_category_rel',
  114. 'category_id',
  115. 'emp_id', '员工')
  116. company_id = fields.Many2one(
  117. 'res.company',
  118. string='公司',
  119. change_default=True,
  120. default=lambda self: self.env.company)
  121. color = fields.Integer(string='分类颜色', default=_get_default_color)
  122. _sql_constraints = [
  123. ('name_uniq', 'unique (name)', "分类标签已经存在!"),
  124. ]
  125. class Staff(models.Model):
  126. _inherit = 'staff'
  127. _inherits = {'auxiliary.financing': 'auxiliary_id'}
  128. _order = 'department_id, work_no'
  129. @api.onchange('job_id')
  130. def onchange_job_id(self):
  131. '''选择职位时带出部门和部门经理'''
  132. if self.job_id:
  133. self.department_id = self.job_id.department_id
  134. self.parent_id = self.job_id.department_id.manager_id
  135. # @api.constrains('work_email')
  136. # def _check_work_email(selfs):
  137. # ''' 验证 work_email 合法性 '''
  138. # for self in selfs:
  139. # if self.work_email:
  140. # res = re.match('^[a-zA-Z0-9_-_.]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$', self.work_email)
  141. # if not res:
  142. # raise UserError('请检查邮箱格式是否正确: %s' % self.work_email)
  143. def _sync_user(self, user):
  144. vals = dict(
  145. image_medium=user.image_1920,
  146. work_email=user.email if user.email else '',
  147. user_id=user.id,
  148. )
  149. return vals
  150. auxiliary_id = fields.Many2one(
  151. string='辅助核算',
  152. comodel_name='auxiliary.financing',
  153. ondelete='restrict',
  154. required=True,
  155. )
  156. category_ids = fields.Many2many('staff.employee.category',
  157. 'staff_employee_category_rel',
  158. 'emp_id',
  159. 'category_id', string='标签')
  160. work_email = fields.Char(string='办公邮箱')
  161. work_phone = fields.Char(string='办公电话')
  162. image_medium = fields.Image(string='头像',attachment=True)
  163. # 个人信息
  164. birthday = fields.Date(string='生日')
  165. # identification_id = fields.Char(string='证照号码')
  166. is_arbeitnehmer = fields.Boolean(string='是否雇员', default='1')
  167. is_investoren = fields.Boolean(string='是否投资者')
  168. is_bsw = fields.Boolean(string='是否残疾烈属孤老')
  169. gender = fields.Selection([
  170. ('male', '男'),
  171. ('female', '女')
  172. ], string='性别')
  173. marital = fields.Selection([
  174. ('single', '单身'),
  175. ('married', '已婚'),
  176. ('widower', '丧偶'),
  177. ('divorced', '离异')
  178. ], string='婚姻状况')
  179. contract_ids = fields.One2many('staff.contract', 'staff_id', string='合同')
  180. active = fields.Boolean(string='启用', default=True)
  181. # 公开信息
  182. work_mobile = fields.Char(string='办公手机')
  183. department_id = fields.Many2one('staff.department', string='部门')
  184. parent_id = fields.Many2one('staff', string='部门经理')
  185. job_id = fields.Many2one('staff.job', string='职位')
  186. notes = fields.Text(string='其他信息')
  187. emergency_contact = fields.Char(string='紧急联系人')
  188. emergency_call = fields.Char(string='紧急联系方式')
  189. bank_name = fields.Char(string='工资卡号')
  190. bank_num = fields.Char(string='工资卡开户行')
  191. @api.model
  192. def staff_contract_over_date(self):
  193. # 员工合同到期,发送邮件给员工 和 部门经理(如果存在)
  194. now = datetime.now().strftime("%Y-%m-%d")
  195. for Staff in self.search([]):
  196. if not Staff.contract_ids:
  197. continue
  198. for contract in Staff.contract_ids:
  199. if now == contract.over_date:
  200. self.env.ref('staff.contract_over_due_date_employee').send_mail(
  201. self.env.user.id)
  202. if Staff.parent_id and Staff.parent_id.work_email:
  203. self.env.ref('staff.contract_over_due_date_manager').send_mail(
  204. self.env.user.id)
  205. return
  206. # ===========================
  207. # @Time : 2020/12/24 16:23
  208. # @Author : Jason Zou
  209. # @Email : zou.jason@qq.com
  210. # 以下扩展员工个人信息
  211. # ===========================
  212. work_no = fields.Char(string='员工工号')
  213. work_date = fields.Date(string='参加工作日期', )
  214. join_date = fields.Date(string='加入本司日期', )
  215. training_date = fields.Date(string='新员工培训日期', )
  216. confirm_date = fields.Date(string='转正日期', )
  217. spouse_complete_name = fields.Char(string='配偶全名', )
  218. spouse_birthdate = fields.Date(string='配偶生日', )
  219. km_home_work = fields.Char(string='家和公司之间的距离', )
  220. contract_category_id = fields.Many2one('core.value',
  221. string='合同类别',
  222. ondelete='restrict',
  223. domain=[('type', '=', 'contract_category')],
  224. context={'type': 'contract_category'})
  225. confident_agreement_id = fields.Many2one('core.value',
  226. string='保密协议类别',
  227. ondelete='restrict',
  228. domain=[('type', '=', 'confident_agreement')],
  229. context={'type': 'confident_agreement'})
  230. job_type_id = fields.Many2one('core.value',
  231. string='岗位类型',
  232. ondelete='restrict',
  233. domain=[('type', '=', 'job_type')],
  234. context={'type': 'job_type'})
  235. reimbursement_card = fields.Char(string='报销卡号', )
  236. account_reimbursement_card = fields.Char(string='报销卡开户行', )
  237. professional_title_id = fields.Many2one('core.value',
  238. string='职称',
  239. ondelete='restrict',
  240. domain=[('type', '=', 'professional_title')],
  241. context={'type': 'professional_title'})
  242. graduation_certificate_id = fields.Many2one('core.value',
  243. string='证书',
  244. ondelete='restrict',
  245. domain=[('type', '=', 'graduation_certificate')],
  246. context={'type': 'graduation_certificate'})
  247. children = fields.Char(string='子女数', )
  248. child_one = fields.Char(string='子女1姓名', )
  249. child_one_birthday = fields.Date(string='子女1出生日期', )
  250. child_two = fields.Char(string='子女2姓名', )
  251. child_two_birthday = fields.Date(string='子女2出生日期', )
  252. relationship_one_id = fields.Many2one('core.value',
  253. string='关系',
  254. ondelete='restrict',
  255. domain=[('type', '=', 'relationship_one')],
  256. context={'type': 'relationship_one'})
  257. second_contact = fields.Char(string='第二紧急联系人', )
  258. relationship_two_id = fields.Many2one('core.value',
  259. string='第二紧急联系人关系',
  260. ondelete='restrict',
  261. domain=[('type', '=', 'relationship_two')],
  262. context={'type': 'relationship_two'})
  263. second_contact_tel = fields.Char(string='第二紧急联系人电话', )
  264. archives_place = fields.Char(string='档案存放地', )
  265. leaving_reason_id = fields.Many2one('core.value',
  266. string='离职原因',
  267. ondelete='restrict',
  268. domain=[('type', '=', 'leaving_reason')],
  269. context={'type': 'leaving_reason'})
  270. last_working = fields.Date(string='最后工作日', )
  271. salary_date = fields.Date(string='工资结算日', )
  272. duration_agreement = fields.Char(string='培训协议期限', )
  273. political_outlook_id = fields.Many2one('core.value',
  274. string='政治面貌',
  275. ondelete='restrict',
  276. domain=[('type', '=', 'political_outlook')],
  277. context={'type': 'political_outlook'})
  278. nation_id = fields.Many2one('core.value',
  279. string='民族',
  280. ondelete='restrict',
  281. domain=[('type', '=', 'nation_ch')],
  282. context={'type': 'nation_ch'})
  283. native_place = fields.Char(string='籍贯', )
  284. household_registration_id = fields.Many2one('core.value',
  285. string='户籍类型',
  286. ondelete='restrict',
  287. domain=[('type', '=', 'household_registration')],
  288. context={'type': 'household_registration'})
  289. actual_residence = fields.Char(string='实际居住地住址', )
  290. highest_education_id = fields.Many2one('core.value',
  291. string='最高学历',
  292. ondelete='restrict',
  293. domain=[('type', '=', 'highest_education')],
  294. context={'type': 'highest_education'})
  295. major_title_id = fields.Many2one('core.value',
  296. string='专业',
  297. ondelete='restrict',
  298. domain=[('type', '=', 'major_title')],
  299. context={'type': 'major_title'})
  300. university_graduated_id = fields.Many2one('core.value',
  301. string='毕业院校',
  302. ondelete='restrict',
  303. domain=[('type', '=', 'university_graduated')],
  304. context={'type': 'university_graduated'})
  305. learning_form_id = fields.Many2one('core.value',
  306. string='学历性质',
  307. ondelete='restrict',
  308. domain=[('type', '=', 'learning_form')],
  309. context={'type': 'learning_form'})
  310. graduation_date = fields.Date(string='毕业时间', )
  311. social_payment_address_id = fields.Many2one('core.value',
  312. string='社保公积金缴纳地点',
  313. ondelete='restrict',
  314. domain=[('type', '=', 'social_payment_address')],
  315. context={'type': 'social_payment_address'})
  316. commercial_insurance = fields.Char(string='商保号', )
  317. social_security_account = fields.Char(string='社保账号', )
  318. provident_fund_account = fields.Char(string='公积金账号', )
  319. @api.model_create_multi
  320. def create(self, vals_list):
  321. for vals in vals_list:
  322. if vals.get('user_id'):
  323. user = self.env['res.users'].browse(vals['user_id'])
  324. vals.update(self._sync_user(user))
  325. vals['name'] = vals.get('name', user.name)
  326. return super().create(vals_list)
  327. def write(self, vals):
  328. if vals.get('user_id'):
  329. vals.update(self._sync_user(self.env['res.users'].browse(vals['user_id'])))
  330. return super().write(vals)
  331. def name_get(self):
  332. result = []
  333. for record in self:
  334. if record.work_no and record.name:
  335. result.append((record.id, '[' + record.work_no + ']' + record.name))
  336. elif record.name and (not record.work_no):
  337. result.append((record.id, record.name))
  338. return result
  339. @api.model
  340. def name_search(self, name, args=None, operator='ilike', limit=100):
  341. args = args or []
  342. staff_ids = []
  343. if name:
  344. staff_ids = self.search(['|', ('work_no', '=', name), ('name', '=', name)] + args, limit=limit)
  345. if not staff_ids:
  346. staff_ids = self.search(['|', ('work_no', operator, name), ('name', operator, name)] + args, limit=limit)
  347. return staff_ids.name_get()
  348. @api.depends('work_no', 'name')
  349. def _compute_display_name(self):
  350. for line in self:
  351. work_no_part = f"[{line.work_no}]" if line.work_no else ""
  352. name_part = line.name or ""
  353. line.display_name = f"{work_no_part}{name_part}"
上海开阖软件有限公司 沪ICP备12045867号-1