diff --git a/gvsds/apps/gerp/apps/ehrm/models.py b/gvsds/apps/gerp/apps/ehrm/models.py index 479aceff..5c80a144 100644 --- a/gvsds/apps/gerp/apps/ehrm/models.py +++ b/gvsds/apps/gerp/apps/ehrm/models.py @@ -9,21 +9,52 @@ from gvsds.model_base import QModel class EmployeeProfile(QModel): - """员工档案表——eHRM:员工基本信息与任职档案""" + """员工档案表——eHRM:员工基本信息与任职档案 + + 人员归属只认「部门员工关联」(UserRoleDepartmentUUID,表单虚拟列): + 落库解析出 UserUUID / DeptUUID,员工名称与部门名称前端由关联解析展示(不在本表存名字)。 + PositionName 是**只读联动**展示列(取该员工 UserRoleDepartmentPosition 的真实职务),不由表单填写。 + """ EmployeeProfileUUID = UUIDField(primary_key=True, verbose_name='档案UUID') UserUUID = UUIDField(db_column='UserUUID', db_index=True, verbose_name='员工用户UUID') TenantUUID = UUIDField(null=True, blank=True, db_column='TenantUUID', verbose_name='租户UUID') CompanyUUID = UUIDField(db_column='CompanyUUID', verbose_name='公司UUID') DeptUUID = UUIDField(null=True, blank=True, db_column='DeptUUID', verbose_name='部门UUID') + # DeptName 保留列(历史数据兼容):新档案不再写入,展示改用 DeptUUID 关联解析 DeptName = models.CharField(max_length=64, default='', verbose_name='部门名称') - EmployeeNo = models.CharField(max_length=32, default='', verbose_name='工号') HireDate = models.DateField(null=True, blank=True, verbose_name='入职日期') PositionName = models.CharField(max_length=64, default='', verbose_name='职务') + # ===== 基本信息 ===== + EmployeeName = models.CharField(max_length=64, default='', verbose_name='姓名') + Gender = models.CharField(max_length=8, default='', verbose_name='性别') + AgeRange = models.CharField(max_length=16, default='', verbose_name='年龄') + Race = models.CharField(max_length=32, default='', verbose_name='种族') + PoliticalStatus = models.CharField(max_length=16, default='', verbose_name='政治面貌') Education = models.CharField(max_length=32, default='', verbose_name='学历') - EmergencyContact = models.CharField(max_length=32, default='', verbose_name='紧急联系人') - EmergencyPhone = models.CharField(max_length=32, default='', verbose_name='紧急联系电话') Address = models.CharField(max_length=256, default='', verbose_name='联系地址') + Birthday = models.DateField(null=True, blank=True, verbose_name='生日') + # ===== 网络与志愿 ===== + Nickname = models.CharField(max_length=64, default='', verbose_name='网络常用昵称') + VolunteerWish = models.TextField(default='', verbose_name='志愿') + VolunteerWork = models.CharField(max_length=16, default='', verbose_name='志愿工作') + VolunteerWorkOther = models.CharField(max_length=64, default='', verbose_name='其它志愿工作') + Industry = models.CharField(max_length=32, default='', verbose_name='从事行业') + # ===== 工作条件 ===== + Devices = models.CharField(max_length=256, default='', verbose_name='可参与工作的设备') + DeviceRemark = models.CharField(max_length=256, default='', verbose_name='设备备注') + AcceptDispatchDevice = models.BooleanField(default=False, verbose_name='是否愿意使用派发设备') + AcceptRewardPunish = models.BooleanField(default=False, verbose_name='是否接受奖罚机制') + ExpectedWorkHours = models.CharField(max_length=128, default='', verbose_name='期望工作时段') + # ===== 健康状况 ===== + PhysicalIllness = models.CharField(max_length=512, default='', verbose_name='躯体疾病') + MentalIllness = models.CharField(max_length=512, default='', verbose_name='精神障碍') + # ===== 紧急联系人 ===== + EmergencyContact = models.CharField(max_length=32, default='', verbose_name='紧急联系人姓名') + EmergencyRelation = models.CharField(max_length=16, default='', verbose_name='与本人关系') + EmergencyRelationOther = models.CharField(max_length=32, default='', verbose_name='其它关系说明') + EmergencyPhone = models.CharField(max_length=32, default='', verbose_name='紧急联系电话') + EmergencyContactCustom = models.CharField(max_length=128, default='', verbose_name='自定义联系方式') Remark = models.CharField(max_length=512, default='', verbose_name='备注') CreateTime = models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='创建时间') @@ -35,6 +66,32 @@ class EmployeeProfile(QModel): verbose_name_plural = '员工档案' +class EmployeeContact(QModel): + """员工联系方式子表——eHRM:一条 = 某份档案的一项联系方式 + + 与 EmployeeProfile 一对多(每次保存档案时整体重写该档案的联系方式明细)。 + ContactType 取值见 form_service.CONTACT_TYPE_OPTIONS(1=微信 2=QQ 3=邮箱 + 4=企业微信 5=X 6=个人网站 7=手机号)。 + """ + + EmployeeContactUUID = UUIDField(primary_key=True, verbose_name='联系方式UUID') + EmployeeProfileUUID = UUIDField(db_column='EmployeeProfileUUID', db_index=True, verbose_name='档案UUID') + UserUUID = UUIDField(null=True, blank=True, db_column='UserUUID', db_index=True, verbose_name='员工用户UUID') + TenantUUID = UUIDField(null=True, blank=True, db_column='TenantUUID', verbose_name='租户UUID') + CompanyUUID = UUIDField(db_column='CompanyUUID', verbose_name='公司UUID') + ContactType = models.SmallIntegerField(default=1, verbose_name='联系方式类型') + ContactValue = models.CharField(max_length=256, default='', verbose_name='联系方式') + ContactSort = models.IntegerField(default=0, verbose_name='排序') + CreateTime = models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='创建时间') + + class Meta: + db_table = 'EmployeeContact' + app_label = 'gerp' + ordering = ['ContactSort', 'CreateTime'] + verbose_name = '员工联系方式' + verbose_name_plural = '员工联系方式' + + class EmployeeAssessment(QModel): """员工考核表——eHRM:考核期间、评分与等级结论""" diff --git a/gvsds/apps/gerp/form_service.py b/gvsds/apps/gerp/form_service.py index cd2da8c5..9ddaf3de 100644 --- a/gvsds/apps/gerp/form_service.py +++ b/gvsds/apps/gerp/form_service.py @@ -1,4 +1,5 @@ import uuid +import json import datetime import re import logging @@ -18,7 +19,7 @@ from gvsds.apps.gerp.models import ( App, AppPosition, AppVirtualPosition, AppVirtualBinding, FinanceVoucher, FinanceVoucherEntry, FinanceCashier, FinanceLedger, FinanceReport, FinanceReimburse, FinanceArap, FinanceBudget, - EmployeeProfile, EmployeeAssessment, EmployeePerformance, + EmployeeProfile, EmployeeContact, EmployeeAssessment, EmployeePerformance, OaLeave, OaTravel, OaMeeting, OaAnnouncement, OaReport, ) from gvsds.apps.core.models import User, UserAvatar, User2FA, UserPending2FA @@ -167,7 +168,8 @@ DEPT_EMPLOYEE_PICKER_MULTI = { #: eHRM 员工档案从「部门员工关联」解析后要落的列 #: (_ResolveDeptEmployee 返回值含 4 个键,各表只取自己表上存在的列,多带键会撞 model(**kwargs)) -_PROFILE_DEPT_EMPLOYEE_KEYS = ('UserUUID', 'DeptUUID', 'DeptName') +#: DeptName 不在此列:部门名称不再写库(展示由 DeptUUID 关联解析),列仅保留给历史数据 +_PROFILE_DEPT_EMPLOYEE_KEYS = ('UserUUID', 'DeptUUID') class FormService(FormServiceBase): @@ -224,6 +226,7 @@ class FormService(FormServiceBase): 'FinanceArap': FinanceArap, 'FinanceBudget': FinanceBudget, 'EmployeeProfile': EmployeeProfile, + 'EmployeeContact': EmployeeContact, 'EmployeeAssessment': EmployeeAssessment, 'EmployeePerformance': EmployeePerformance, 'OaLeave': OaLeave, @@ -527,6 +530,68 @@ class FormService(FormServiceBase): ], } + # ==================== eHRM 员工档案(EmployeeProfile)选项模板 ==================== + # 「模板」= 系统统一维护的选项常量(后端唯一下发,前端只渲染,禁止就地另写一份) + # 名称型选项统一**存中文文本**(列表直接可读,无需再映射);类型型(ContactType)存数字。 + EMPLOYEE_PROFILE_SELECT_OPTIONS = { + 'Gender': ['男', '女', '其他'], + 'AgeRange': ['12~18', '19~25', '26~40', '41~65', '66以上'], + 'PoliticalStatus': ['群众', '共青团员', '中共党员', '民主党派', '其他'], + 'Education': ['小学', '初中', '高中', '中专', '大专', '本科', '硕士', '博士', '其他'], + 'VolunteerWork': ['程序员', '画师', '测试者', '其它'], + 'Industry': [ + 'IT/通信/电子/互联网', + '金融业', + '房地产/建筑业', + '商业服务', + '贸易/批发/零售/租赁业', + '文体教育/工艺美术', + '生产/加工/制造', + '交通/运输/物流/仓储', + '服务业', + '文化/传媒/娱乐/体育', + '能源/矿产/环保', + '政府/非盈利机构', + '学校', + ], + 'EmergencyRelation': ['父子', '母子', '配偶', '其它'], + } + + #: 档案里的多选字段(tags 类型:选项固定 + 允许自定义,逗号分隔字符串存储) + EMPLOYEE_PROFILE_TAGS_OPTIONS = { + 'Devices': ['电脑', '手机', '云服务器'], + 'PhysicalIllness': [ + '无', '先天发育畸形', '纹身', '内分泌、营养、代谢疾病', '泌尿生殖系统疾病', + '心血管疾病', '神经科疾病', '残疾', '消化系统疾病', '其他', + ], + 'MentalIllness': [ + '无', '焦虑症', '抑郁症', '强迫症', '惊恐障碍', '单相情感障碍', '双相情感障碍', '其他', + ], + } + + #: 档案里用多行文本框的字段(长文本) + EMPLOYEE_PROFILE_TEXTAREA_FIELDS = ('VolunteerWish', 'Remark') + + #: 档案表单里不需要用户选/填的字段: + #: 人员由「部门员工关联」一次选定,员工名/部门名/职务/部门名冗余列一律只读展示 + EMPLOYEE_PROFILE_FORM_HIDDEN_FIELDS = ( + 'UserUUID', 'DeptUUID', 'DeptName', 'PositionName', 'TenantUUID', 'CompanyUUID', + ) + + #: 联系方式类型(EmployeeContact.ContactType):子表一行 = 一种渠道 + CONTACT_TYPE_OPTIONS = [ + {'value': 1, 'label': '微信'}, + {'value': 2, 'label': 'QQ'}, + {'value': 3, 'label': '邮箱'}, + {'value': 4, 'label': '企业微信'}, + {'value': 5, 'label': 'X'}, + {'value': 6, 'label': '个人网站'}, + {'value': 7, 'label': '手机号'}, + ] + + #: 档案表单里「联系方式」子表的虚拟列名(值 = 明细行数组,随档案一并提交) + EMPLOYEE_CONTACT_FIELD = 'Contacts' + def get_columns(self, table_name): model = self.TABLE_MAP.get(table_name) if not model: @@ -930,10 +995,63 @@ class FormService(FormServiceBase): col['editable'] = False col['hideInForm'] = True col['visible'] = False - # EmployeeProfile 直接绑「部门-员工」关系:员工/部门/部门名由虚拟列 - # UserRoleDepartmentUUID 一次选定,故三者在表单中隐藏(列表仍展示) - if table_name == 'EmployeeProfile' and pascal_name in ('UserUUID', 'DeptUUID', 'DeptName'): - col['hideInForm'] = True + # ===== eHRM 员工档案(EmployeeProfile):选项模板 + 只读联动列 ===== + # 人员/部门由虚拟列「部门员工关联」一次选定;员工名/部门名/职务都是**只读联动** + # 展示(员工名与部门名来自关联 label,职务取该员工真实职务),一律不进表单。 + if table_name == 'EmployeeProfile': + if pascal_name in self.EMPLOYEE_PROFILE_SELECT_OPTIONS: + col['type'] = 'select' + col['options'] = [ + {'value': _v, 'label': _v} + for _v in self.EMPLOYEE_PROFILE_SELECT_OPTIONS[pascal_name] + ] + col['placeholder'] = f"选择{col['title']}" + if pascal_name in self.EMPLOYEE_PROFILE_TAGS_OPTIONS: + # 多选:选项固定 + 允许自定义新增(满足「其它」),逗号分隔字符串存储 + col['type'] = 'tags' + col['options'] = [ + {'value': _v, 'label': _v} + for _v in self.EMPLOYEE_PROFILE_TAGS_OPTIONS[pascal_name] + ] + col['tagsSeparator'] = ',' + col['placeholder'] = f"选择{col['title']}(可多选,可自定义)" + if pascal_name in self.EMPLOYEE_PROFILE_TEXTAREA_FIELDS: + col['type'] = 'textarea' + if pascal_name in ('AcceptDispatchDevice', 'AcceptRewardPunish'): + col['type'] = 'switch' + col['defaultValue'] = False + if pascal_name in self.EMPLOYEE_PROFILE_FORM_HIDDEN_FIELDS: + col['editable'] = False + col['hideInForm'] = True + if pascal_name == 'DeptName': + # 部门名称不再由档案维护:展示改用 DeptUUID 关联解析(DeptUUID_label) + col['visible'] = False + if pascal_name == 'UserUUID': + col['title'] = '员工名称' + col['editable'] = False + if pascal_name == 'DeptUUID': + col['title'] = '部门名称' + col['editable'] = False + if pascal_name == 'PositionName': + # 职务只读联动:值由 get_table 从该员工 UserRoleDepartmentPosition 取真实职务 + col['editable'] = False + # EmployeeContact(员工联系方式子表):只作为档案表单内嵌子表使用 + # (列定义经 EmployeeProfile 的虚拟列 subform 下发,前端按此渲染增删行) + if table_name == 'EmployeeContact': + if pascal_name == 'ContactType': + col['title'] = '联系方式类型' + col['type'] = 'select' + col['options'] = [dict(_o) for _o in self.CONTACT_TYPE_OPTIONS] + col['required'] = True + col['placeholder'] = '选择类型' + elif pascal_name == 'ContactValue': + col['title'] = '联系方式' + col['required'] = True + col['placeholder'] = '如微信号 / 邮箱地址 / 手机号' + elif pascal_name == 'ContactSort': + col['type'] = 'number' + col['visible'] = False + col['hideInForm'] = True if table_name == 'EmployeeAssessment' and pascal_name == 'UserUUID': col['title'] = '员工' if table_name == 'EmployeeAssessment' and pascal_name == 'AssessorUUID': @@ -1119,11 +1237,16 @@ class FormService(FormServiceBase): 'visible': False, # 仅表单可见(列表已拆成"用户/角色"两列展示) }) columns = virtual_cols + columns - # EmployeeProfile(员工档案)虚拟列"部门员工关联":直接选一条用户-角色-部门关系 - # (UserRoleDepartment),选中即同时确定员工(UserUUID)与部门(DeptUUID/DeptName); - # 写库由 add_record / modify_record 解析该 UUID,列表仍展示真实列(员工/部门)。 - # 选择器复用 DEPT_EMPLOYEE_PICKER(与工作组新增成员同一组件:按部门树分组浏览) + # EmployeeProfile(员工档案)两张虚拟列: + # 1) 「部门员工关联」(置顶):选一条 UserRoleDepartment,选中即确定员工与部门; + # 写库由 add_record / modify_record 解析该 UUID,列表仍展示真实列(员工/部门) + # 2) 「联系方式」子表单(置于表单末尾):明细行数组随档案一起提交, + # 保存后由 _RewriteEmployeeContacts 整体重写 EmployeeContact 子表 if table_name == 'EmployeeProfile': + _contact_fields = [ + _c for _c in self.get_columns('EmployeeContact') + if _c.get('field') in ('ContactType', 'ContactValue', 'ContactSort') + ] columns = [{ 'field': 'UserRoleDepartmentUUID', 'title': '部门员工关联', @@ -1137,7 +1260,23 @@ class FormService(FormServiceBase): # 新增缺省校验由后端在 add_record 内做(提示更精确) 'required': False, 'visible': False, # 仅表单可见:列表已有"员工/部门"真实列 - }] + columns + }] + columns + [{ + 'field': self.EMPLOYEE_CONTACT_FIELD, + 'title': '联系方式', + 'titleEn': self.EMPLOYEE_CONTACT_FIELD, + 'type': 'subform', + 'subform': { + 'table': 'EmployeeContact', + 'title': '联系方式', + 'addText': '添加联系方式', + 'fields': _contact_fields, + }, + 'editable': True, + 'sortable': False, + 'filterable': False, + 'required': False, + 'visible': False, # 仅表单可见(列表不展示明细行) + }] # 表单字段顺序:「部门员工关联」选择器置顶 —— 新增时先选它,员工/部门/角色随之确定, # 其余字段(职务/类型等)都是派生或可选的 if table_name in self.DEPT_EMPLOYEE_FIRST_TABLES: @@ -1555,6 +1694,23 @@ class FormService(FormServiceBase): _prof_dept_names = _StrKeyMap(DepartmentManager.GetDepartmentNameMap( [_urd.DeptUUID for _urd in _prof_pair.values() if _urd.DeptUUID] )) + # 职务只读联动:各档案对应「部门员工关联」的职务集合(UserRoleDepartmentPosition) + _prof_urd_ids = [ + _pu for _pu in ( + getattr(_u, 'UserRoleDepartmentUUID', None) for _u in _prof_pair.values() + ) if _pu + ] + _prof_pos_map = {} + if _prof_urd_ids: + _prof_pos_rows = PositionManager.GetUrdPositionRowsForUrds(_prof_urd_ids) + _prof_pos_names = _StrKeyMap(PositionManager.GetPositionNameMap( + {_p.PositionUUID for _p in _prof_pos_rows if _p.PositionUUID} + )) + for _p in _prof_pos_rows: + _prod_key = _ProfStr(_p.UserRoleDepartmentUUID) + _prof_pos_map.setdefault(_prod_key, []).append( + _prof_pos_names.get(_ProfStr(_p.PositionUUID)) or _ProfStr(_p.PositionUUID) + ) for r in records: _urd = _prof_pair.get((_ProfStr(r.get('UserUUID')), _ProfStr(r.get('DeptUUID')))) if _urd is None: @@ -1565,6 +1721,29 @@ class FormService(FormServiceBase): r['UserRoleDepartmentUUID_label'] = ( f'{_dn} · {_un}' if (_dn or _un) else r['UserRoleDepartmentUUID'] ) + _pl = _prof_pos_map.get(_ProfStr(_urd.UserRoleDepartmentUUID), []) + r['PositionName'] = '、'.join(_pl) + r['PositionName_label'] = r['PositionName'] + # 联系方式子表明细(子表单回显):一次查出本页所有档案的明细行。 + # 键统一用 UUIDObj 的字符串形式(模型读出来是 UUIDObj,记录字典里是字符串, + # 必须同一形态才能对上,见 _StrKeyMap 的同类说明) + _prof_uuids = [r.get('EmployeeProfileUUID') for r in records if r.get('EmployeeProfileUUID')] + if _prof_uuids: + _contact_map = {} + for _ct in EmployeeContact.objects.filter( + EmployeeProfileUUID__in=[_to_uuid_bytes(_x) for _x in _prof_uuids]): + _contact_map.setdefault(str(_ct.EmployeeProfileUUID), []).append({ + 'ContactType': _ct.ContactType, + 'ContactValue': _ct.ContactValue, + 'ContactSort': _ct.ContactSort, + }) + for r in records: + _raw_pk = r.get('EmployeeProfileUUID') + _prof_key = str(UUIDObj(_to_uuid_bytes(_raw_pk))) if _raw_pk else '' + _rows = _contact_map.get(_prof_key, []) + r[self.EMPLOYEE_CONTACT_FIELD] = sorted( + _rows, key=lambda _x: _x.get('ContactSort') or 0 + ) except Exception as e: import logging logging.error('[FormService] get_table error: table=%s, error=%s', table_name, e, exc_info=True) @@ -1618,6 +1797,62 @@ class FormService(FormServiceBase): 'UserRoleUUID': user_role_bytes, }, None + def _ParseContactsPayload(self, data): + """解析档案表单提交的「联系方式」子表明细(虚拟列 Contacts) + + 一行 = {ContactType, ContactValue};空值行丢弃,行序即排序(ContactSort)。 + + Returns: + list[dict] | None: 未提交该字段返回 None(调用方据此保持原明细不动) + """ + raw = data.get(self.EMPLOYEE_CONTACT_FIELD) + if raw is None: + return None + if isinstance(raw, str): + try: + raw = json.loads(raw) + except Exception: + return [] + if not isinstance(raw, (list, tuple)): + return [] + rows = [] + for _i, _item in enumerate(raw): + if not isinstance(_item, dict): + continue + _value = str(_item.get('ContactValue') or '').strip() + if not _value: + continue # 空行(用户加了行没填)直接丢弃 + try: + _ctype = int(_item.get('ContactType') or 1) + except (TypeError, ValueError): + _ctype = 1 + rows.append({'ContactType': _ctype, 'ContactValue': _value, 'ContactSort': _i}) + return rows + + def _RewriteEmployeeContacts(self, profile, rows): + """按提交的明细整体重写某份档案的联系方式子表(rows=None 表示未提交,保持不动)""" + if rows is None: + return + profile_uuid = _to_uuid_bytes(getattr(profile, 'EmployeeProfileUUID', None)) + if not profile_uuid: + return + try: + EmployeeContact.objects.filter(EmployeeProfileUUID=profile_uuid).delete() + except Exception: + logger.warning('[FormService] 清理员工联系方式失败: profile=%s', profile_uuid, exc_info=True) + return + for _row in rows: + EmployeeContact.objects.create( + EmployeeContactUUID=uuid.uuid4().bytes, + EmployeeProfileUUID=profile_uuid, + UserUUID=_to_uuid_bytes(getattr(profile, 'UserUUID', None)), + TenantUUID=_to_uuid_bytes(getattr(profile, 'TenantUUID', None)), + CompanyUUID=_to_uuid_bytes(getattr(profile, 'CompanyUUID', None)), + ContactType=_row['ContactType'], + ContactValue=_row['ContactValue'], + ContactSort=_row['ContactSort'], + ) + def add_record(self, data): table_name = data.get('Table', '') model = self.TABLE_MAP.get(table_name) @@ -2003,6 +2238,10 @@ class FormService(FormServiceBase): CompanyUUID=getattr(_urd, 'CompanyUUID', None), TenantUUID=getattr(_urd, 'TenantUUID', None), ) + # EmployeeProfile(员工档案):联系方式子表(虚拟列 Contacts)随档案一并提交, + # 主表没有该列 → 档案落库后按提交明细整体重写子表(未提交该字段则保持原明细) + if table_name == 'EmployeeProfile': + self._RewriteEmployeeContacts(obj, self._ParseContactsPayload(data)) # 审计日志:记录新增操作 self._record_audit(table_name, 'add', target_obj=obj, new_data=self._get_record_snapshot(obj)) # 工单创建:指派了处理人则通知对方(MsgType=2 工单通知) @@ -2251,6 +2490,10 @@ class FormService(FormServiceBase): self._send_workorder_notify(obj, _receiver, _wo_title, _wo_content) if update_fields: self._SaveObject(obj, update_fields) + # EmployeeProfile(员工档案):联系方式子表(虚拟列 Contacts)随档案一并提交, + # 主表没有该列 → 保存后按提交明细整体重写子表(未提交该字段则保持原明细) + if table_name == 'EmployeeProfile': + self._RewriteEmployeeContacts(obj, self._ParseContactsPayload(data)) # UserRole 表(员工列表)编辑"部门/职务":UserRole 自身无这两个字段(虚拟列), # 提交时同步关系表 UserRoleDepartment(主关联:该 UserRole+公司首条)与职务子表 if table_name == 'UserRole' and ('DeptUUID' in data or 'PositionUUID' in data or 'PositionUUID_id' in data): diff --git a/gvsds/apps/gerp/migrations/0048_employee_profile_rebuild.py b/gvsds/apps/gerp/migrations/0048_employee_profile_rebuild.py new file mode 100644 index 00000000..a1f2116f --- /dev/null +++ b/gvsds/apps/gerp/migrations/0048_employee_profile_rebuild.py @@ -0,0 +1,133 @@ +"""员工档案(EmployeeProfile)字段重建 + 新增联系方式子表(EmployeeContact) + +删除 EmployeeNo(工号);新增姓名/性别/年龄/种族/政治面貌/生日、网络昵称/志愿/志愿工作、 +从事行业、可参与工作的设备与备注、派发设备与奖罚机制意愿、期望工作时段、躯体疾病/精神障碍、 +紧急联系人的关系与自定义联系方式;保留入职日期/职务(只读联动)/学历/地址/紧急联系人/备注。 +新表 EmployeeContact 存档案的联系方式明细(档案 1:N)。 + +手写迁移:自动生成会夹带 communitycategory 等既有漂移,并触发交互式重命名询问。 +""" +import datetime + +from django.db import migrations, models + +import gvsds.apps.core.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('gerp', '0047_app_pending_scope'), + ] + + operations = [ + migrations.RemoveField(model_name='employeeprofile', name='EmployeeNo'), + migrations.AlterField( + model_name='employeeprofile', name='EmergencyContact', + field=models.CharField(default='', max_length=32, verbose_name='紧急联系人姓名'), + ), + migrations.AddField( + model_name='employeeprofile', name='EmployeeName', + field=models.CharField(default='', max_length=64, verbose_name='姓名'), + ), + migrations.AddField( + model_name='employeeprofile', name='Gender', + field=models.CharField(default='', max_length=8, verbose_name='性别'), + ), + migrations.AddField( + model_name='employeeprofile', name='AgeRange', + field=models.CharField(default='', max_length=16, verbose_name='年龄'), + ), + migrations.AddField( + model_name='employeeprofile', name='Race', + field=models.CharField(default='', max_length=32, verbose_name='种族'), + ), + migrations.AddField( + model_name='employeeprofile', name='PoliticalStatus', + field=models.CharField(default='', max_length=16, verbose_name='政治面貌'), + ), + migrations.AddField( + model_name='employeeprofile', name='Birthday', + field=models.DateField(blank=True, null=True, verbose_name='生日'), + ), + migrations.AddField( + model_name='employeeprofile', name='Nickname', + field=models.CharField(default='', max_length=64, verbose_name='网络常用昵称'), + ), + migrations.AddField( + model_name='employeeprofile', name='VolunteerWish', + field=models.TextField(default='', verbose_name='志愿'), + ), + migrations.AddField( + model_name='employeeprofile', name='VolunteerWork', + field=models.CharField(default='', max_length=16, verbose_name='志愿工作'), + ), + migrations.AddField( + model_name='employeeprofile', name='VolunteerWorkOther', + field=models.CharField(default='', max_length=64, verbose_name='其它志愿工作'), + ), + migrations.AddField( + model_name='employeeprofile', name='Industry', + field=models.CharField(default='', max_length=32, verbose_name='从事行业'), + ), + migrations.AddField( + model_name='employeeprofile', name='Devices', + field=models.CharField(default='', max_length=256, verbose_name='可参与工作的设备'), + ), + migrations.AddField( + model_name='employeeprofile', name='DeviceRemark', + field=models.CharField(default='', max_length=256, verbose_name='设备备注'), + ), + migrations.AddField( + model_name='employeeprofile', name='AcceptDispatchDevice', + field=models.BooleanField(default=False, verbose_name='是否愿意使用派发设备'), + ), + migrations.AddField( + model_name='employeeprofile', name='AcceptRewardPunish', + field=models.BooleanField(default=False, verbose_name='是否接受奖罚机制'), + ), + migrations.AddField( + model_name='employeeprofile', name='ExpectedWorkHours', + field=models.CharField(default='', max_length=128, verbose_name='期望工作时段'), + ), + migrations.AddField( + model_name='employeeprofile', name='PhysicalIllness', + field=models.CharField(default='', max_length=512, verbose_name='躯体疾病'), + ), + migrations.AddField( + model_name='employeeprofile', name='MentalIllness', + field=models.CharField(default='', max_length=512, verbose_name='精神障碍'), + ), + migrations.AddField( + model_name='employeeprofile', name='EmergencyRelation', + field=models.CharField(default='', max_length=16, verbose_name='与本人关系'), + ), + migrations.AddField( + model_name='employeeprofile', name='EmergencyRelationOther', + field=models.CharField(default='', max_length=32, verbose_name='其它关系说明'), + ), + migrations.AddField( + model_name='employeeprofile', name='EmergencyContactCustom', + field=models.CharField(default='', max_length=128, verbose_name='自定义联系方式'), + ), + migrations.CreateModel( + name='EmployeeContact', + fields=[ + ('EmployeeContactUUID', gvsds.apps.core.models.UUIDField(primary_key=True, serialize=False, verbose_name='联系方式UUID')), + ('EmployeeProfileUUID', gvsds.apps.core.models.UUIDField(db_column='EmployeeProfileUUID', db_index=True, verbose_name='档案UUID')), + ('UserUUID', gvsds.apps.core.models.UUIDField(blank=True, db_column='UserUUID', db_index=True, null=True, verbose_name='员工用户UUID')), + ('TenantUUID', gvsds.apps.core.models.UUIDField(blank=True, db_column='TenantUUID', null=True, verbose_name='租户UUID')), + ('CompanyUUID', gvsds.apps.core.models.UUIDField(db_column='CompanyUUID', verbose_name='公司UUID')), + ('ContactType', models.SmallIntegerField(default=1, verbose_name='联系方式类型')), + ('ContactValue', models.CharField(default='', max_length=256, verbose_name='联系方式')), + ('ContactSort', models.IntegerField(default=0, verbose_name='排序')), + ('CreateTime', models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='创建时间')), + ], + options={ + 'db_table': 'EmployeeContact', + 'ordering': ['ContactSort', 'CreateTime'], + 'verbose_name': '员工联系方式', + 'verbose_name_plural': '员工联系方式', + }, + ), + ]