GoodERP
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 satır
17KB

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