GoodERP
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

411 lines
18KB

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