diff --git a/sql/sqlserver/ruoyi-vue-pro.sql b/sql/sqlserver/ruoyi-vue-pro.sql index ae49821..5b6be1f 100644 --- a/sql/sqlserver/ruoyi-vue-pro.sql +++ b/sql/sqlserver/ruoyi-vue-pro.sql @@ -43,7 +43,7 @@ CREATE TABLE infra_api_access_log ( id bigint NOT NULL PRIMARY KEY IDENTITY, trace_id nvarchar(64) DEFAULT '' NOT NULL, user_id bigint DEFAULT 0 NOT NULL, - user_type tinyint DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, application_name nvarchar(50) NOT NULL, request_method nvarchar(16) DEFAULT '' NOT NULL, request_url nvarchar(255) DEFAULT '' NOT NULL, @@ -53,7 +53,7 @@ CREATE TABLE infra_api_access_log ( user_agent nvarchar(512) NOT NULL, operate_module nvarchar(50) DEFAULT NULL NULL, operate_name nvarchar(50) DEFAULT NULL NULL, - operate_type tinyint DEFAULT 0 NULL, + operate_type smallint DEFAULT 0 NULL, begin_time datetime2 NOT NULL, end_time datetime2 NOT NULL, duration int NOT NULL, @@ -260,7 +260,7 @@ CREATE TABLE infra_api_error_log ( id bigint NOT NULL PRIMARY KEY IDENTITY, trace_id nvarchar(64) NOT NULL, user_id bigint DEFAULT 0 NOT NULL, - user_type tinyint DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, application_name nvarchar(50) NOT NULL, request_method nvarchar(16) NOT NULL, request_url nvarchar(255) NOT NULL, @@ -276,7 +276,7 @@ CREATE TABLE infra_api_error_log ( exception_file_name nvarchar(512) NOT NULL, exception_method_name nvarchar(512) NOT NULL, exception_line_number int NOT NULL, - process_status tinyint NOT NULL, + process_status smallint NOT NULL, process_time datetime2 DEFAULT NULL NULL, process_user_id int DEFAULT 0 NULL, creator nvarchar(64) DEFAULT '' NULL, @@ -503,18 +503,18 @@ CREATE TABLE infra_codegen_column ( column_name nvarchar(200) NOT NULL, data_type nvarchar(100) NOT NULL, column_comment nvarchar(500) NOT NULL, - nullable varchar(1) NOT NULL, - primary_key varchar(1) NOT NULL, + nullable bit NOT NULL, + primary_key bit NOT NULL, ordinal_position int NOT NULL, java_type nvarchar(32) NOT NULL, java_field nvarchar(64) NOT NULL, dict_type nvarchar(200) DEFAULT '' NULL, example nvarchar(64) DEFAULT NULL NULL, - create_operation varchar(1) NOT NULL, - update_operation varchar(1) NOT NULL, - list_operation varchar(1) NOT NULL, + create_operation bit NOT NULL, + update_operation bit NOT NULL, + list_operation bit NOT NULL, list_operation_condition nvarchar(32) DEFAULT '=' NOT NULL, - list_operation_result varchar(1) NOT NULL, + list_operation_result bit NOT NULL, html_type nvarchar(32) NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -701,7 +701,7 @@ GO CREATE TABLE infra_codegen_table ( id bigint NOT NULL PRIMARY KEY IDENTITY, data_source_config_id bigint NOT NULL, - scene tinyint DEFAULT 1 NOT NULL, + scene smallint DEFAULT 1 NOT NULL, table_name nvarchar(200) DEFAULT '' NOT NULL, table_comment nvarchar(500) DEFAULT '' NOT NULL, remark nvarchar(500) DEFAULT NULL NULL, @@ -710,12 +710,12 @@ CREATE TABLE infra_codegen_table ( class_name nvarchar(100) DEFAULT '' NOT NULL, class_comment nvarchar(50) NOT NULL, author nvarchar(50) NOT NULL, - template_type tinyint DEFAULT 1 NOT NULL, - front_type tinyint NOT NULL, + template_type smallint DEFAULT 1 NOT NULL, + front_type smallint NOT NULL, parent_menu_id bigint DEFAULT NULL NULL, master_table_id bigint DEFAULT NULL NULL, sub_join_column_id bigint DEFAULT NULL NULL, - sub_join_many varchar(1) DEFAULT NULL NULL, + sub_join_many bit DEFAULT NULL NULL, tree_parent_column_id bigint DEFAULT NULL NULL, tree_name_column_id bigint DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, @@ -907,11 +907,11 @@ GO CREATE TABLE infra_config ( id bigint NOT NULL PRIMARY KEY IDENTITY, category nvarchar(50) NOT NULL, - type tinyint NOT NULL, + type smallint NOT NULL, name nvarchar(100) DEFAULT '' NOT NULL, config_key nvarchar(100) DEFAULT '' NOT NULL, value nvarchar(500) DEFAULT '' NOT NULL, - visible varchar(1) NOT NULL, + visible bit NOT NULL, remark nvarchar(500) DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -1260,9 +1260,9 @@ GO CREATE TABLE infra_file_config ( id bigint NOT NULL PRIMARY KEY IDENTITY, name nvarchar(63) NOT NULL, - storage tinyint NOT NULL, + storage smallint NOT NULL, remark nvarchar(255) DEFAULT NULL NULL, - master varchar(1) NOT NULL, + master bit NOT NULL, config nvarchar(4000) NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -1487,7 +1487,7 @@ GO CREATE TABLE infra_job ( id bigint NOT NULL PRIMARY KEY IDENTITY, name nvarchar(32) NOT NULL, - status tinyint NOT NULL, + status smallint NOT NULL, handler_name nvarchar(64) NOT NULL, handler_param nvarchar(255) DEFAULT NULL NULL, cron_expression nvarchar(32) NOT NULL, @@ -1687,11 +1687,11 @@ CREATE TABLE infra_job_log ( job_id bigint NOT NULL, handler_name nvarchar(64) NOT NULL, handler_param nvarchar(255) DEFAULT NULL NULL, - execute_index tinyint DEFAULT 1 NOT NULL, + execute_index smallint DEFAULT 1 NOT NULL, begin_time datetime2 NOT NULL, end_time datetime2 DEFAULT NULL NULL, duration int DEFAULT NULL NULL, - status tinyint NOT NULL, + status smallint NOT NULL, result nvarchar(4000) DEFAULT '' NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -1829,7 +1829,7 @@ CREATE TABLE system_dept ( leader_user_id bigint DEFAULT NULL NULL, phone nvarchar(11) DEFAULT NULL NULL, email nvarchar(50) DEFAULT NULL NULL, - status tinyint NOT NULL, + status smallint NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, updater nvarchar(64) DEFAULT '' NULL, @@ -1999,7 +1999,7 @@ CREATE TABLE system_dict_data ( label nvarchar(100) DEFAULT '' NOT NULL, value nvarchar(100) DEFAULT '' NOT NULL, dict_type nvarchar(100) DEFAULT '' NOT NULL, - status tinyint DEFAULT 0 NOT NULL, + status smallint DEFAULT 0 NOT NULL, color_type nvarchar(100) DEFAULT '' NULL, css_class nvarchar(100) DEFAULT '' NULL, remark nvarchar(500) DEFAULT NULL NULL, @@ -5251,7 +5251,7 @@ CREATE TABLE system_dict_type ( id bigint NOT NULL PRIMARY KEY IDENTITY, name nvarchar(100) DEFAULT '' NOT NULL, type nvarchar(100) DEFAULT '' NOT NULL, - status tinyint DEFAULT 0 NOT NULL, + status smallint DEFAULT 0 NOT NULL, remark nvarchar(500) DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -6056,9 +6056,9 @@ CREATE TABLE system_login_log ( log_type bigint NOT NULL, trace_id nvarchar(64) DEFAULT '' NOT NULL, user_id bigint DEFAULT 0 NOT NULL, - user_type tinyint DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, username nvarchar(50) DEFAULT '' NOT NULL, - result tinyint NOT NULL, + result smallint NOT NULL, user_ip nvarchar(50) NOT NULL, user_agent nvarchar(512) NOT NULL, creator nvarchar(64) DEFAULT '' NULL, @@ -6197,8 +6197,8 @@ CREATE TABLE system_mail_account ( password nvarchar(255) NOT NULL, host nvarchar(255) NOT NULL, port int NOT NULL, - ssl_enable varchar(1) DEFAULT '0' NOT NULL, - starttls_enable varchar(1) DEFAULT '0' NOT NULL, + ssl_enable bit DEFAULT 0 NOT NULL, + starttls_enable bit DEFAULT 0 NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, updater nvarchar(64) DEFAULT '' NULL, @@ -6333,7 +6333,7 @@ GO CREATE TABLE system_mail_log ( id bigint NOT NULL PRIMARY KEY IDENTITY, user_id bigint DEFAULT NULL NULL, - user_type tinyint DEFAULT NULL NULL, + user_type smallint DEFAULT NULL NULL, to_mails nvarchar(1024) NOT NULL, cc_mails nvarchar(1024) DEFAULT NULL NULL, bcc_mails nvarchar(1024) DEFAULT NULL NULL, @@ -6345,7 +6345,7 @@ CREATE TABLE system_mail_log ( template_title nvarchar(255) NOT NULL, template_content nvarchar(max) NOT NULL, template_params nvarchar(255) NOT NULL, - send_status tinyint DEFAULT 0 NOT NULL, + send_status smallint DEFAULT 0 NOT NULL, send_time datetime2 DEFAULT NULL NULL, send_message_id nvarchar(255) DEFAULT NULL NULL, send_exception nvarchar(4000) DEFAULT NULL NULL, @@ -6537,7 +6537,7 @@ CREATE TABLE system_mail_template ( title nvarchar(255) NOT NULL, content nvarchar(4000) NOT NULL, params nvarchar(255) NOT NULL, - status tinyint NOT NULL, + status smallint NOT NULL, remark nvarchar(255) DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -6686,17 +6686,17 @@ CREATE TABLE system_menu ( id bigint NOT NULL PRIMARY KEY IDENTITY, name nvarchar(50) NOT NULL, permission nvarchar(100) DEFAULT '' NOT NULL, - type tinyint NOT NULL, + type smallint NOT NULL, sort int DEFAULT 0 NOT NULL, parent_id bigint DEFAULT 0 NOT NULL, path nvarchar(200) DEFAULT '' NULL, icon nvarchar(100) DEFAULT '#' NULL, component nvarchar(255) DEFAULT NULL NULL, component_name nvarchar(255) DEFAULT NULL NULL, - status tinyint DEFAULT 0 NOT NULL, - visible varchar(1) DEFAULT '1' NOT NULL, - keep_alive varchar(1) DEFAULT '1' NOT NULL, - always_show varchar(1) DEFAULT '1' NOT NULL, + status smallint DEFAULT 0 NOT NULL, + visible bit DEFAULT 1 NOT NULL, + keep_alive bit DEFAULT 1 NOT NULL, + always_show bit DEFAULT 1 NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, updater nvarchar(64) DEFAULT '' NULL, @@ -11190,8 +11190,8 @@ CREATE TABLE system_notice ( id bigint NOT NULL PRIMARY KEY IDENTITY, title nvarchar(50) NOT NULL, content nvarchar(max) NOT NULL, - type tinyint NOT NULL, - status tinyint DEFAULT 0 NOT NULL, + type smallint NOT NULL, + status smallint DEFAULT 0 NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, updater nvarchar(64) DEFAULT '' NULL, @@ -11311,14 +11311,14 @@ GO CREATE TABLE system_notify_message ( id bigint NOT NULL PRIMARY KEY IDENTITY, user_id bigint NOT NULL, - user_type tinyint NOT NULL, + user_type smallint NOT NULL, template_id bigint NOT NULL, template_code nvarchar(64) NOT NULL, template_nickname nvarchar(63) NOT NULL, template_content nvarchar(1024) NOT NULL, template_type int NOT NULL, template_params nvarchar(255) NOT NULL, - read_status varchar(1) NOT NULL, + read_status bit NOT NULL, read_time datetime2 DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -11671,9 +11671,9 @@ CREATE TABLE system_notify_template ( code nvarchar(64) NOT NULL, nickname nvarchar(255) NOT NULL, content nvarchar(1024) NOT NULL, - type tinyint NOT NULL, + type smallint NOT NULL, params nvarchar(255) DEFAULT NULL NULL, - status tinyint NOT NULL, + status smallint NOT NULL, remark nvarchar(255) DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -11794,7 +11794,7 @@ GO CREATE TABLE system_oauth2_access_token ( id bigint NOT NULL PRIMARY KEY IDENTITY, user_id bigint NOT NULL, - user_type tinyint NOT NULL, + user_type smallint NOT NULL, user_info nvarchar(512) NOT NULL, access_token nvarchar(255) NOT NULL, refresh_token nvarchar(32) NOT NULL, @@ -11933,10 +11933,10 @@ GO CREATE TABLE system_oauth2_approve ( id bigint NOT NULL PRIMARY KEY IDENTITY, user_id bigint NOT NULL, - user_type tinyint NOT NULL, + user_type smallint NOT NULL, client_id nvarchar(255) NOT NULL, scope nvarchar(255) DEFAULT '' NOT NULL, - approved varchar(1) DEFAULT '0' NOT NULL, + approved bit DEFAULT 0 NOT NULL, expires_time datetime2 NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -12058,7 +12058,7 @@ CREATE TABLE system_oauth2_client ( name nvarchar(255) NOT NULL, logo nvarchar(255) NOT NULL, description nvarchar(255) DEFAULT NULL NULL, - status tinyint NOT NULL, + status smallint NOT NULL, access_token_validity_seconds int NOT NULL, refresh_token_validity_seconds int NOT NULL, redirect_uris nvarchar(255) NOT NULL, @@ -12261,7 +12261,7 @@ GO CREATE TABLE system_oauth2_code ( id bigint NOT NULL PRIMARY KEY IDENTITY, user_id bigint NOT NULL, - user_type tinyint NOT NULL, + user_type smallint NOT NULL, code nvarchar(32) NOT NULL, client_id nvarchar(255) NOT NULL, scopes nvarchar(255) DEFAULT '' NULL, @@ -12399,7 +12399,7 @@ CREATE TABLE system_oauth2_refresh_token ( id bigint NOT NULL PRIMARY KEY IDENTITY, user_id bigint NOT NULL, refresh_token nvarchar(32) NOT NULL, - user_type tinyint NOT NULL, + user_type smallint NOT NULL, client_id nvarchar(255) NOT NULL, scopes nvarchar(255) DEFAULT NULL NULL, expires_time datetime2 NOT NULL, @@ -12520,12 +12520,12 @@ CREATE TABLE system_operate_log ( id bigint NOT NULL PRIMARY KEY IDENTITY, trace_id nvarchar(64) DEFAULT '' NOT NULL, user_id bigint NOT NULL, - user_type tinyint DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, type nvarchar(50) NOT NULL, sub_type nvarchar(50) NOT NULL, biz_id bigint NOT NULL, action nvarchar(2000) DEFAULT '' NOT NULL, - success varchar(1) DEFAULT '1' NOT NULL, + success bit DEFAULT 1 NOT NULL, extra nvarchar(2000) DEFAULT '' NOT NULL, request_method nvarchar(16) DEFAULT '' NULL, request_url nvarchar(255) DEFAULT '' NULL, @@ -12700,7 +12700,7 @@ CREATE TABLE system_post ( code nvarchar(64) NOT NULL, name nvarchar(50) NOT NULL, sort int NOT NULL, - status tinyint NOT NULL, + status smallint NOT NULL, remark nvarchar(500) DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -12832,10 +12832,10 @@ CREATE TABLE system_role ( name nvarchar(30) NOT NULL, code nvarchar(100) NOT NULL, sort int NOT NULL, - data_scope tinyint DEFAULT 1 NOT NULL, + data_scope smallint DEFAULT 1 NOT NULL, data_scope_dept_ids nvarchar(500) DEFAULT '' NOT NULL, - status tinyint NOT NULL, - type tinyint NOT NULL, + status smallint NOT NULL, + type smallint NOT NULL, remark nvarchar(500) DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -16200,7 +16200,7 @@ CREATE TABLE system_sms_channel ( id bigint NOT NULL PRIMARY KEY IDENTITY, signature nvarchar(12) NOT NULL, code nvarchar(63) NOT NULL, - status tinyint NOT NULL, + status smallint NOT NULL, remark nvarchar(255) DEFAULT NULL NULL, api_key nvarchar(128) NOT NULL, api_secret nvarchar(128) DEFAULT NULL NULL, @@ -16339,9 +16339,9 @@ CREATE TABLE system_sms_code ( mobile nvarchar(11) NOT NULL, code nvarchar(6) NOT NULL, create_ip nvarchar(15) NOT NULL, - scene tinyint NOT NULL, - today_index tinyint NOT NULL, - used tinyint NOT NULL, + scene smallint NOT NULL, + today_index smallint NOT NULL, + used smallint NOT NULL, used_time datetime2 DEFAULT NULL NULL, used_ip nvarchar(255) DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, @@ -16477,20 +16477,20 @@ CREATE TABLE system_sms_log ( channel_code nvarchar(63) NOT NULL, template_id bigint NOT NULL, template_code nvarchar(63) NOT NULL, - template_type tinyint NOT NULL, + template_type smallint NOT NULL, template_content nvarchar(255) NOT NULL, template_params nvarchar(255) NOT NULL, api_template_id nvarchar(63) NOT NULL, mobile nvarchar(11) NOT NULL, user_id bigint DEFAULT NULL NULL, - user_type tinyint DEFAULT NULL NULL, - send_status tinyint DEFAULT 0 NOT NULL, + user_type smallint DEFAULT NULL NULL, + send_status smallint DEFAULT 0 NOT NULL, send_time datetime2 DEFAULT NULL NULL, api_send_code nvarchar(63) DEFAULT NULL NULL, api_send_msg nvarchar(255) DEFAULT NULL NULL, api_request_id nvarchar(255) DEFAULT NULL NULL, api_serial_no nvarchar(255) DEFAULT NULL NULL, - receive_status tinyint DEFAULT 0 NOT NULL, + receive_status smallint DEFAULT 0 NOT NULL, receive_time datetime2 DEFAULT NULL NULL, api_receive_code nvarchar(63) DEFAULT NULL NULL, api_receive_msg nvarchar(255) DEFAULT NULL NULL, @@ -16703,8 +16703,8 @@ DROP TABLE IF EXISTS system_sms_template GO CREATE TABLE system_sms_template ( id bigint NOT NULL PRIMARY KEY IDENTITY, - type tinyint NOT NULL, - status tinyint NOT NULL, + type smallint NOT NULL, + status smallint NOT NULL, code nvarchar(63) NOT NULL, name nvarchar(63) NOT NULL, content nvarchar(255) NOT NULL, @@ -16890,13 +16890,13 @@ GO CREATE TABLE system_social_client ( id bigint NOT NULL PRIMARY KEY IDENTITY, name nvarchar(255) NOT NULL, - social_type tinyint NOT NULL, - user_type tinyint NOT NULL, + social_type smallint NOT NULL, + user_type smallint NOT NULL, client_id nvarchar(255) NOT NULL, client_secret nvarchar(255) NOT NULL, agent_id nvarchar(255) DEFAULT NULL NULL, public_key nvarchar(2048) DEFAULT NULL NULL, - status tinyint NOT NULL, + status smallint NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, updater nvarchar(64) DEFAULT '' NULL, @@ -17053,7 +17053,7 @@ DROP TABLE IF EXISTS system_social_user GO CREATE TABLE system_social_user ( id bigint NOT NULL PRIMARY KEY IDENTITY, - type tinyint NOT NULL, + type smallint NOT NULL, openid nvarchar(32) NOT NULL, token nvarchar(256) DEFAULT NULL NULL, raw_token_info nvarchar(1024) NOT NULL, @@ -17201,8 +17201,8 @@ GO CREATE TABLE system_social_user_bind ( id bigint NOT NULL PRIMARY KEY IDENTITY, user_id bigint NOT NULL, - user_type tinyint NOT NULL, - social_type tinyint NOT NULL, + user_type smallint NOT NULL, + social_type smallint NOT NULL, social_user_id bigint NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -17309,7 +17309,7 @@ CREATE TABLE system_tenant ( contact_user_id bigint DEFAULT NULL NULL, contact_name nvarchar(30) NOT NULL, contact_mobile nvarchar(500) DEFAULT NULL NULL, - status tinyint DEFAULT 0 NOT NULL, + status smallint DEFAULT 0 NOT NULL, websites nvarchar(1024) DEFAULT '' NULL, package_id bigint NOT NULL, expire_time datetime2 NOT NULL, @@ -17460,7 +17460,7 @@ GO CREATE TABLE system_tenant_package ( id bigint NOT NULL PRIMARY KEY IDENTITY, name nvarchar(30) NOT NULL, - status tinyint DEFAULT 0 NOT NULL, + status smallint DEFAULT 0 NOT NULL, remark nvarchar(256) DEFAULT '' NULL, menu_ids nvarchar(4000) NOT NULL, creator nvarchar(64) DEFAULT '' NOT NULL, @@ -17850,9 +17850,9 @@ CREATE TABLE system_users ( post_ids nvarchar(255) DEFAULT NULL NULL, email nvarchar(50) DEFAULT '' NULL, mobile nvarchar(11) DEFAULT '' NULL, - sex tinyint DEFAULT 0 NULL, + sex smallint DEFAULT 0 NULL, avatar nvarchar(512) DEFAULT '' NULL, - status tinyint DEFAULT 0 NOT NULL, + status smallint DEFAULT 0 NOT NULL, login_ip nvarchar(50) DEFAULT '' NULL, login_date datetime2 DEFAULT NULL NULL, creator nvarchar(64) DEFAULT '' NULL, @@ -18082,7 +18082,7 @@ GO CREATE TABLE yudao_demo01_contact ( id bigint NOT NULL PRIMARY KEY IDENTITY, name nvarchar(100) DEFAULT '' NOT NULL, - sex tinyint NOT NULL, + sex smallint NOT NULL, birthday datetime2 NOT NULL, description nvarchar(255) NOT NULL, avatar nvarchar(512) DEFAULT NULL NULL, @@ -18323,7 +18323,7 @@ CREATE TABLE yudao_demo03_course ( id bigint NOT NULL PRIMARY KEY IDENTITY, student_id bigint NOT NULL, name nvarchar(100) DEFAULT '' NOT NULL, - score tinyint NOT NULL, + score smallint NOT NULL, creator nvarchar(64) DEFAULT '' NULL, create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, updater nvarchar(64) DEFAULT '' NULL, @@ -18578,7 +18578,7 @@ GO CREATE TABLE yudao_demo03_student ( id bigint NOT NULL PRIMARY KEY IDENTITY, name nvarchar(100) DEFAULT '' NOT NULL, - sex tinyint NOT NULL, + sex smallint NOT NULL, birthday datetime2 NOT NULL, description nvarchar(255) NOT NULL, creator nvarchar(64) DEFAULT '' NULL, diff --git a/sql/tools/convertor.py b/sql/tools/convertor.py index b2e804a..22b8d06 100644 --- a/sql/tools/convertor.py +++ b/sql/tools/convertor.py @@ -800,9 +800,20 @@ class SQLServerConvertor(Convertor): if type in ("datetime", "timestamp"): return "datetime2" if type == "bit": - return "varchar(1)" + # MySQL bit(1) 与 SQL Server bit 均只有 0、1、NULL;多位的位串不是布尔值,暂不支持 + if size not in (None, 1): + raise ValueError(f"SQL Server 转换暂不支持 bit({size}),仅支持 bit(1)") + return "bit" + # SQL Server 的 tinyint 为 0 ~ 255,smallint 为 -32768 ~ 32767,需要选择能容纳 MySQL 取值范围的类型 if type in ("tinyint", "smallint"): + # 有符号:MySQL tinyint 为 -128 ~ 127,smallint 为 -32768 ~ 32767 + return "smallint" + if type == "tinyint unsigned": + # 无符号:0 ~ 255 return "tinyint" + if type == "smallint unsigned": + # 无符号:0 ~ 65535 + return "int" if type in ("text", "longtext"): return "nvarchar(max)" if type in ("blob", "mediumblob"): @@ -825,7 +836,11 @@ class SQLServerConvertor(Convertor): type = col["type"].lower() full_type = self.translate_type(type, col["size"]) nullable = "NULL" if col["nullable"] else "NOT NULL" - default = f"DEFAULT {col['default']}" if col["default"] is not None else "" + default_value = col["default"] + # bit 的默认值使用数字常量:b'0'、b'1' 在清理后为 '0'、'1' + if full_type == "bit" and default_value in ("'0'", "'1'"): + default_value = default_value.strip("'") + default = f"DEFAULT {default_value}" if default_value is not None else "" return f"{name} {full_type} {default} {nullable}" table_name = ddl["table_name"].lower() diff --git a/sql/tools/test_convertor.py b/sql/tools/test_convertor.py index 8090c7a..910b209 100644 --- a/sql/tools/test_convertor.py +++ b/sql/tools/test_convertor.py @@ -286,6 +286,130 @@ INSERT INTO `demo_bom` (`id`, `name`) VALUES (1, 'a\ufeffb'); self.assertNotIn("Table structure for ghost", out) +class SQLServerConvertorTest(unittest.TestCase): + # MySQL 整数取值范围:https://dev.mysql.com/doc/refman/8.4/en/integer-types.html + MYSQL_INTEGER_RANGES = { + "tinyint": (-128, 127), + "tinyint unsigned": (0, 255), + "smallint": (-32768, 32767), + "smallint unsigned": (0, 65535), + } + # SQL Server 整数取值范围:https://learn.microsoft.com/sql/t-sql/data-types/int-bigint-smallint-and-tinyint-transact-sql + SQLSERVER_INTEGER_RANGES = { + "tinyint": (0, 255), + "smallint": (-32768, 32767), + "int": (-2 ** 31, 2 ** 31 - 1), + "bigint": (-2 ** 63, 2 ** 63 - 1), + } + + TYPE_TABLE = """ +DROP TABLE IF EXISTS `demo_type`; +CREATE TABLE `demo_type` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `grade` tinyint NOT NULL DEFAULT 0 COMMENT '有符号 tinyint', + `sex` tinyint(1) NOT NULL DEFAULT 0 COMMENT '性别', + `score` smallint NOT NULL DEFAULT 0 COMMENT '有符号 smallint', + `ratio` tinyint unsigned NOT NULL DEFAULT 255 COMMENT '无符号 tinyint', + `port` smallint unsigned NOT NULL DEFAULT 65535 COMMENT '无符号 smallint', + `enabled` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否启用', + `visible` bit(1) NULL DEFAULT NULL COMMENT '是否可见', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '类型表'; + +BEGIN; +INSERT INTO `demo_type` (`id`, `grade`, `sex`, `score`, `ratio`, `port`, `enabled`, `visible`, `deleted`) VALUES (1, -128, 1, -32768, 255, 65535, b'0', NULL, b'0'); +INSERT INTO `demo_type` (`id`, `grade`, `sex`, `score`, `ratio`, `port`, `enabled`, `visible`, `deleted`) VALUES (2, 127, 0, 32767, 0, 0, b'1', b'1', b'0'); +COMMIT; +""" + + def setUp(self): + directory = tempfile.TemporaryDirectory() + self.addCleanup(directory.cleanup) + self.directory = directory.name + + def write_sql(self, content): + path = os.path.join(self.directory, "dump.sql") + with open(path, "w", encoding="utf-8") as f: + f.write(content) + return path + + def test_translate_type_integer_range(self): + convertor = SQLServerConvertor(self.write_sql(HEADER + DEMO_TABLE)) + for mysql_type, (mysql_min, mysql_max) in self.MYSQL_INTEGER_RANGES.items(): + with self.subTest(mysql_type): + target_type = convertor.translate_type(mysql_type, None) + target_min, target_max = self.SQLSERVER_INTEGER_RANGES[target_type] + # 目标类型需要容纳负数、大于 255 等全部取值 + self.assertLessEqual(target_min, mysql_min) + self.assertGreaterEqual(target_max, mysql_max) + # tinyint(1) 的显示宽度不影响取值范围 + self.assertEqual("smallint", convertor.translate_type("tinyint", 1)) + # 无符号 tinyint 保持 tinyint,不扩大类型 + self.assertEqual("tinyint", convertor.translate_type("TINYINT UNSIGNED", None)) + + def test_translate_type_bit(self): + convertor = SQLServerConvertor(self.write_sql(HEADER + DEMO_TABLE)) + self.assertEqual("bit", convertor.translate_type("bit", 1)) + self.assertEqual("bit", convertor.translate_type("bit", None)) + # 多位的位串不是布尔值,不能转换为 bit + with self.assertRaises(ValueError): + convertor.translate_type("bit", 8) + + def test_integer_and_bit(self): + out, err = convert(SQLServerConvertor(self.write_sql(HEADER + self.TYPE_TABLE))) + self.assertNotIn("无法正常解析", err) + # 有符号 tinyint、smallint:smallint + self.assertIn("grade smallint DEFAULT 0 NOT NULL", out) + self.assertIn("sex smallint DEFAULT 0 NOT NULL", out) + self.assertIn("score smallint DEFAULT 0 NOT NULL", out) + # 无符号 tinyint:tinyint;无符号 smallint:int + self.assertIn("ratio tinyint DEFAULT 255 NOT NULL", out) + self.assertIn("port int DEFAULT 65535 NOT NULL", out) + # bit(1):bit,默认值为数字常量,允许 NULL + self.assertIn("enabled bit DEFAULT 1 NOT NULL", out) + self.assertIn("visible bit DEFAULT NULL NULL", out) + self.assertIn("deleted bit DEFAULT 0 NOT NULL", out) + self.assertNotIn("varchar(1)", out) + # INSERT 保留负数、大于 255 的取值;bit 的 '0'、'1' 由 SQL Server 隐式转换 + self.assertIn("INSERT INTO demo_type (id, grade, sex, score, ratio, port, enabled, visible, deleted)" + " VALUES (1, -128, 1, -32768, 255, 65535, N'0', NULL, N'0')\nGO", out) + self.assertIn("INSERT INTO demo_type (id, grade, sex, score, ratio, port, enabled, visible, deleted)" + " VALUES (2, 127, 0, 32767, 0, 0, N'1', N'1', N'0')\nGO", out) + + def test_bit_multiple(self): + sql = HEADER + """ +CREATE TABLE `demo_flags` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `flags` bit(8) NOT NULL COMMENT '位串', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT = '位串表'; +""" + # 明确失败,不把多位的位串当成布尔值 + with self.assertRaises(ValueError): + convert(SQLServerConvertor(self.write_sql(sql))) + + def test_ruoyi_vue_pro(self): + convertor = SQLServerConvertor(os.path.join(MYSQL_DIR, "ruoyi-vue-pro.sql")) + source_bits, source_integers = [], [] + for table_sql in convertor.original_table_script_list: + source_bits += re.findall(r"^\s*`(\w+)`\s+bit\b[^\n]*", table_sql, flags=re.MULTILINE) + source_integers += re.findall(r"^\s*`\w+`\s+(?:tinyint|smallint)\b[^\n]*", table_sql, flags=re.MULTILINE) + self.assertTrue(source_bits) + self.assertTrue(source_integers) + # 官方脚本只有 bit(1)、有符号的 tinyint / smallint + for table_sql in convertor.original_table_script_list: + self.assertFalse(re.findall(r"^\s*`\w+`\s+bit\((?!1\))", table_sql, flags=re.MULTILINE)) + self.assertFalse([line for line in source_integers if "unsigned" in line.lower()]) + + out, err = convert(convertor) + self.assertNotIn("无法正常解析", err) + self.assertNotIn("varchar(1)", out) + self.assertEqual(len(source_bits), len(re.findall(r"^ \w+ bit\b", out, flags=re.MULTILINE))) + self.assertEqual(len(source_integers), len(re.findall(r"^ \w+ smallint\b", out, flags=re.MULTILINE))) + self.assertFalse(re.findall(r"^ \w+ tinyint\b", out, flags=re.MULTILINE)) + + class ConvertorOfficialDumpTest(unittest.TestCase): def test_ruoyi_vue_pro(self): diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index be0556b..4c685ef 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -112,6 +112,11 @@ spring-boot-starter-test test + + org.mockito + mockito-inline + test + diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerBooleanTypeHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerBooleanTypeHandler.java new file mode 100644 index 0000000..3204155 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerBooleanTypeHandler.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +/** + * Boolean 的类型转换器实现类,对应数据库的整数类型(tinyint、smallint、int2、number 等) + * + * 写入时 true 存 1、false 存 0;读取时非 0 为 true、0 为 false、NULL 为 null。 + * 用于数据库列是整数、而 Java 字段是 Boolean 的场景,避免 PostgreSQL 等数据库不允许 boolean 与整数隐式转换。 + * + * 使用时在字段上配置 {@code @TableField(typeHandler = IntegerBooleanTypeHandler.class)}, + * 并在实体上开启 {@code @TableName(autoResultMap = true)},使查询结果也使用该转换器。 + * 自定义 SQL 或 Wrapper 的独立参数需显式指定此转换器。 + * + * 注意:仅按字段使用, + * 不要注册为全局的 Boolean 类型转换器,否则会影响真正的 boolean / bit 列。 + * + * @author 芋道源码 + */ +public class IntegerBooleanTypeHandler extends BaseTypeHandler { + + @Override + public void setParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException { + if (parameter == null) { + // 未显式指定 jdbcType 时,按整数类型写入 NULL,避免 JdbcType.OTHER 在部分驱动上无法推断类型 + ps.setNull(i, jdbcType == null || jdbcType == JdbcType.OTHER ? Types.INTEGER : jdbcType.TYPE_CODE); + return; + } + setNonNullParameter(ps, i, parameter, jdbcType); + } + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException { + ps.setInt(i, parameter ? 1 : 0); + } + + @Override + public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException { + int value = rs.getInt(columnName); + return rs.wasNull() ? null : value != 0; + } + + @Override + public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + int value = rs.getInt(columnIndex); + return rs.wasNull() ? null : value != 0; + } + + @Override + public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + int value = cs.getInt(columnIndex); + return cs.wasNull() ? null : value != 0; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerBooleanTypeHandlerTest.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerBooleanTypeHandlerTest.java new file mode 100644 index 0000000..8f9dafa --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerBooleanTypeHandlerTest.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import org.apache.ibatis.type.JdbcType; +import org.junit.jupiter.api.Test; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * {@link IntegerBooleanTypeHandler} 的单元测试 + * + * @author 芋道源码 + */ +public class IntegerBooleanTypeHandlerTest { + + private final IntegerBooleanTypeHandler handler = new IntegerBooleanTypeHandler(); + + // ========== 写入 ========== + + @Test + public void testSetParameter_true() throws SQLException { + PreparedStatement ps = mock(PreparedStatement.class); + + handler.setParameter(ps, 1, true, null); + + verify(ps).setInt(1, 1); + verify(ps, never()).setBoolean(anyInt(), anyBoolean()); + } + + @Test + public void testSetParameter_false() throws SQLException { + PreparedStatement ps = mock(PreparedStatement.class); + + handler.setParameter(ps, 2, false, JdbcType.TINYINT); + + verify(ps).setInt(2, 0); + } + + @Test + public void testSetParameter_nullWithoutJdbcType() throws SQLException { + PreparedStatement ps = mock(PreparedStatement.class); + + // MyBatis 未指定 jdbcType 时,可能传入 null 或 jdbcTypeForNull 默认的 OTHER + handler.setParameter(ps, 1, null, null); + handler.setParameter(ps, 2, null, JdbcType.OTHER); + + verify(ps).setNull(1, Types.INTEGER); + verify(ps).setNull(2, Types.INTEGER); + } + + @Test + public void testSetParameter_nullWithJdbcType() throws SQLException { + PreparedStatement ps = mock(PreparedStatement.class); + + handler.setParameter(ps, 1, null, JdbcType.SMALLINT); + + verify(ps).setNull(1, Types.SMALLINT); + } + + // ========== 读取 ========== + + @Test + public void testGetResult_byColumnName() throws SQLException { + ResultSet rs = mock(ResultSet.class); + when(rs.getInt("used")).thenReturn(1, 0, 2, 0); + when(rs.wasNull()).thenReturn(false, false, false, true); + + assertEquals(Boolean.TRUE, handler.getResult(rs, "used")); + assertEquals(Boolean.FALSE, handler.getResult(rs, "used")); + assertEquals(Boolean.TRUE, handler.getResult(rs, "used")); // 非 0 均为 true + assertNull(handler.getResult(rs, "used")); // NULL + } + + @Test + public void testGetResult_byColumnIndex() throws SQLException { + ResultSet rs = mock(ResultSet.class); + when(rs.getInt(3)).thenReturn(1, 0, 0); + when(rs.wasNull()).thenReturn(false, false, true); + + assertEquals(Boolean.TRUE, handler.getResult(rs, 3)); + assertEquals(Boolean.FALSE, handler.getResult(rs, 3)); + assertNull(handler.getResult(rs, 3)); + } + + @Test + public void testGetResult_callableStatement() throws SQLException { + CallableStatement cs = mock(CallableStatement.class); + when(cs.getInt(1)).thenReturn(1, 0, 0); + when(cs.wasNull()).thenReturn(false, false, true); + + assertEquals(Boolean.TRUE, handler.getResult(cs, 1)); + assertEquals(Boolean.FALSE, handler.getResult(cs, 1)); + assertNull(handler.getResult(cs, 1)); + } + +} diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/slip/HrmSalarySlipTemplateDO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/slip/HrmSalarySlipTemplateDO.java index b13ed40..b013f81 100644 --- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/slip/HrmSalarySlipTemplateDO.java +++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/slip/HrmSalarySlipTemplateDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.hrm.dal.dataobject.salary.slip; import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.config.HrmSalaryOptionDO; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import cn.iocoder.yudao.module.hrm.enums.salary.slip.HrmSalarySlipTemplateOptionTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; @@ -20,6 +20,8 @@ import java.util.List; /** * HRM 工资条模板 DO * + * 平台级默认模板保存在 {@link cn.iocoder.yudao.framework.tenant.core.util.TenantUtils#GLOBAL_TENANT_ID} 下,由所有租户只读共享 + * * @author 芋道源码 */ @TableName(value = "hrm_salary_slip_template", autoResultMap = true) @@ -30,7 +32,7 @@ import java.util.List; @Builder @NoArgsConstructor @AllArgsConstructor -public class HrmSalarySlipTemplateDO extends BaseDO { +public class HrmSalarySlipTemplateDO extends TenantBaseDO { /** * 编号 diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/slip/HrmSalarySlipTemplateMapper.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/slip/HrmSalarySlipTemplateMapper.java index 23e2a35..03687e0 100644 --- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/slip/HrmSalarySlipTemplateMapper.java +++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/slip/HrmSalarySlipTemplateMapper.java @@ -26,7 +26,7 @@ public interface HrmSalarySlipTemplateMapper extends BaseMapperX() - .apply("tenant_id = {0}", TenantUtils.GLOBAL_TENANT_ID) + .eq(HrmSalarySlipTemplateDO::getTenantId, TenantUtils.GLOBAL_TENANT_ID) .eq(HrmSalarySlipTemplateDO::getDefaultStatus, true) .orderByDesc(HrmSalarySlipTemplateDO::getId)); } diff --git a/yudao-module-hrm/src/test/java/cn/iocoder/yudao/module/hrm/service/salary/slip/HrmSalarySlipTemplateServiceImplTest.java b/yudao-module-hrm/src/test/java/cn/iocoder/yudao/module/hrm/service/salary/slip/HrmSalarySlipTemplateServiceImplTest.java index 9da2b15..2f9e581 100644 --- a/yudao-module-hrm/src/test/java/cn/iocoder/yudao/module/hrm/service/salary/slip/HrmSalarySlipTemplateServiceImplTest.java +++ b/yudao-module-hrm/src/test/java/cn/iocoder/yudao/module/hrm/service/salary/slip/HrmSalarySlipTemplateServiceImplTest.java @@ -34,6 +34,7 @@ import java.util.Objects; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SALARY_DATA_ILLEGAL; +import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.SALARY_SLIP_TEMPLATE_NOT_EXISTS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -51,6 +52,7 @@ import static org.mockito.Mockito.when; public class HrmSalarySlipTemplateServiceImplTest extends BaseDbUnitTest { private static final Long TENANT_ID = 2L; + private static final Long OTHER_TENANT_ID = 3L; @TestConfiguration(proxyBeanMethods = false) static class TenantTestConfiguration { @@ -108,6 +110,8 @@ public class HrmSalarySlipTemplateServiceImplTest extends BaseDbUnitTest { // 断言 assertNotNull(templateId); HrmSalarySlipTemplateDO template = salarySlipTemplateService.getSalarySlipTemplate(templateId); + // 新增时不传租户编号,由租户拦截器按当前租户填充 + assertEquals(TENANT_ID, template.getTenantId()); assertEquals("研发工资条", template.getName()); assertFalse(template.getHideEmpty()); assertFalse(template.getDefaultStatus()); @@ -173,6 +177,7 @@ public class HrmSalarySlipTemplateServiceImplTest extends BaseDbUnitTest { HrmSalarySlipTemplateDO template = randomPojo(HrmSalarySlipTemplateDO.class, o -> { o.setId(null).setName("默认工资条模板").setHideEmpty(false).setDefaultStatus(true); o.setOptions(Collections.emptyList()); + o.setTenantId(TENANT_ID); }); salarySlipTemplateMapper.insert(template); @@ -258,6 +263,7 @@ public class HrmSalarySlipTemplateServiceImplTest extends BaseDbUnitTest { HrmSalarySlipTemplateDO defaultTemplate = randomPojo(HrmSalarySlipTemplateDO.class, o -> { o.setId(null).setName("默认工资条模板").setHideEmpty(false).setDefaultStatus(true); o.setOptions(Collections.emptyList()); + o.setTenantId(TENANT_ID); }); salarySlipTemplateMapper.insert(defaultTemplate); when(salaryOptionService.getSalaryOptionList(false)).thenReturn(Arrays.asList( @@ -286,11 +292,13 @@ public class HrmSalarySlipTemplateServiceImplTest extends BaseDbUnitTest { HrmSalarySlipTemplateDO globalDefaultTemplate = randomPojo(HrmSalarySlipTemplateDO.class, o -> { o.setId(null).setName("平台默认工资条模板").setHideEmpty(false).setDefaultStatus(true); o.setOptions(Collections.emptyList()); + o.setTenantId(TenantUtils.GLOBAL_TENANT_ID); }); TenantUtils.executeIgnore(() -> salarySlipTemplateMapper.insert(globalDefaultTemplate)); HrmSalarySlipTemplateDO tenantTemplate = randomPojo(HrmSalarySlipTemplateDO.class, o -> { o.setId(null).setName("租户自定义工资条模板").setHideEmpty(false).setDefaultStatus(false); o.setOptions(Collections.emptyList()); + o.setTenantId(TENANT_ID); }); salarySlipTemplateMapper.insert(tenantTemplate); when(salaryOptionService.getSalaryOptionList(false)).thenReturn(Collections.emptyList()); @@ -301,13 +309,73 @@ public class HrmSalarySlipTemplateServiceImplTest extends BaseDbUnitTest { // 断言:普通查询被租户隔离,但 Service 可只读回退平台默认模板 assertNull(salarySlipTemplateMapper.selectById(globalDefaultTemplate.getId())); - assertEquals(globalDefaultTemplate.getId(), - TenantUtils.executeIgnore(salarySlipTemplateMapper::selectGlobalDefaultTemplate).getId()); + HrmSalarySlipTemplateDO dbGlobalDefaultTemplate = + TenantUtils.executeIgnore(salarySlipTemplateMapper::selectGlobalDefaultTemplate); + assertEquals(globalDefaultTemplate.getId(), dbGlobalDefaultTemplate.getId()); + assertEquals(TenantUtils.GLOBAL_TENANT_ID, dbGlobalDefaultTemplate.getTenantId()); assertEquals(globalDefaultTemplate.getId(), salarySlipTemplateService .getSalarySlipTemplate(globalDefaultTemplate.getId()).getId()); assertEquals(2, templates.size()); assertEquals(globalDefaultTemplate.getId(), templates.get(0).getId()); assertEquals(tenantTemplate.getId(), templates.get(1).getId()); + assertEquals(TENANT_ID, templates.get(1).getTenantId()); + + // 调用,并断言:平台默认模板只读,租户不能修改、删除 + HrmSalarySlipTemplateSaveReqVO updateReqVO = randomPojo(HrmSalarySlipTemplateSaveReqVO.class, o -> { + o.setId(globalDefaultTemplate.getId()); + o.setName("租户改写的默认模板"); + o.setOptions(Collections.singletonList(createTemplateOption("基本工资", 10101, 1))); + }); + assertServiceException(() -> salarySlipTemplateService.updateSalarySlipTemplate(updateReqVO), + SALARY_DATA_ILLEGAL); + assertServiceException(() -> salarySlipTemplateService.deleteSalarySlipTemplate(globalDefaultTemplate.getId()), + SALARY_DATA_ILLEGAL); + HrmSalarySlipTemplateDO dbTemplate = TenantUtils.executeIgnore( + () -> salarySlipTemplateMapper.selectById(globalDefaultTemplate.getId())); + assertEquals("平台默认工资条模板", dbTemplate.getName()); + assertEquals(TenantUtils.GLOBAL_TENANT_ID, dbTemplate.getTenantId()); + } + + @Test + public void testSalarySlipTemplate_otherTenantIsolated() { + // mock 数据:其它租户的自定义模板、默认模板,按其它租户的上下文新增 + HrmSalarySlipTemplateDO otherTemplate = randomPojo(HrmSalarySlipTemplateDO.class, o -> { + o.setId(null).setName("其它租户工资条模板").setHideEmpty(false).setDefaultStatus(false); + o.setOptions(Collections.emptyList()); + o.setTenantId(null); + }); + HrmSalarySlipTemplateDO otherDefaultTemplate = randomPojo(HrmSalarySlipTemplateDO.class, o -> { + o.setId(null).setName("其它租户默认工资条模板").setHideEmpty(false).setDefaultStatus(true); + o.setOptions(Collections.emptyList()); + o.setTenantId(null); + }); + TenantUtils.execute(OTHER_TENANT_ID, () -> salarySlipTemplateMapper.insert(otherTemplate)); + TenantUtils.execute(OTHER_TENANT_ID, () -> salarySlipTemplateMapper.insert(otherDefaultTemplate)); + when(salaryOptionService.getSalaryOptionList(false)).thenReturn(Collections.emptyList()); + + // 调用,并断言:当前租户读不到,也不会把其它租户的默认模板当作平台默认模板 + assertNull(salarySlipTemplateMapper.selectById(otherTemplate.getId())); + assertNull(salarySlipTemplateService.getSalarySlipTemplate(otherTemplate.getId())); + assertNull(salarySlipTemplateService.getSalarySlipTemplate(otherDefaultTemplate.getId())); + assertNull(TenantUtils.executeIgnore(salarySlipTemplateMapper::selectGlobalDefaultTemplate)); + assertTrue(salarySlipTemplateService.getSalarySlipTemplateList().isEmpty()); + + // 调用,并断言:当前租户不能修改、删除 + HrmSalarySlipTemplateSaveReqVO updateReqVO = randomPojo(HrmSalarySlipTemplateSaveReqVO.class, o -> { + o.setId(otherTemplate.getId()); + o.setName("当前租户改写的模板"); + o.setOptions(Collections.singletonList(createTemplateOption("基本工资", 10101, 1))); + }); + assertServiceException(() -> salarySlipTemplateService.updateSalarySlipTemplate(updateReqVO), + SALARY_SLIP_TEMPLATE_NOT_EXISTS); + assertServiceException(() -> salarySlipTemplateService.deleteSalarySlipTemplate(otherTemplate.getId()), + SALARY_SLIP_TEMPLATE_NOT_EXISTS); + + // 断言:其它租户的数据不变 + HrmSalarySlipTemplateDO dbTemplate = TenantUtils.executeIgnore( + () -> salarySlipTemplateMapper.selectById(otherTemplate.getId())); + assertEquals("其它租户工资条模板", dbTemplate.getName()); + assertEquals(OTHER_TENANT_ID, dbTemplate.getTenantId()); } @Test diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsCodeDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsCodeDO.java index 63c5481..e6b877e 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsCodeDO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsCodeDO.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.system.dal.dataobject.sms; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerBooleanTypeHandler; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -15,7 +17,7 @@ import java.time.LocalDateTime; * * @author 芋道源码 */ -@TableName("system_sms_code") +@TableName(value = "system_sms_code", autoResultMap = true) @KeySequence("system_sms_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @@ -54,6 +56,7 @@ public class SmsCodeDO extends BaseDO { /** * 是否使用 */ + @TableField(typeHandler = IntegerBooleanTypeHandler.class) private Boolean used; /** * 使用时间 diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImplTest.java index b492f12..8dbe592 100644 --- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImplTest.java +++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImplTest.java @@ -77,7 +77,7 @@ public class SmsCodeServiceImplTest extends BaseDbUnitTest { public void sendSmsCode_tooFast() { // mock 数据 SmsCodeDO smsCodeDO = randomPojo(SmsCodeDO.class, - o -> o.setMobile("15601691300").setTodayIndex(1)); + o -> o.setMobile("15601691300").setTodayIndex(1).setUsed(false)); smsCodeMapper.insert(smsCodeDO); // 准备参数 SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> { @@ -94,7 +94,7 @@ public class SmsCodeServiceImplTest extends BaseDbUnitTest { public void sendSmsCode_exceedDay() { // mock 数据 SmsCodeDO smsCodeDO = randomPojo(SmsCodeDO.class, - o -> o.setMobile("15601691300").setTodayIndex(10).setCreateTime(LocalDateTime.now())); + o -> o.setMobile("15601691300").setTodayIndex(10).setUsed(false).setCreateTime(LocalDateTime.now())); smsCodeMapper.insert(smsCodeDO); // 准备参数 SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> { diff --git a/yudao-module-system/src/test/resources/sql/create_tables.sql b/yudao-module-system/src/test/resources/sql/create_tables.sql index 9970065..8fe671b 100644 --- a/yudao-module-system/src/test/resources/sql/create_tables.sql +++ b/yudao-module-system/src/test/resources/sql/create_tables.sql @@ -321,7 +321,7 @@ CREATE TABLE IF NOT EXISTS "system_sms_code" ( "scene" bigint NOT NULL, "create_ip" varchar NOT NULL, "today_index" int NOT NULL, - "used" bit NOT NULL DEFAULT FALSE, + "used" tinyint NOT NULL DEFAULT 0, "used_time" timestamp DEFAULT NULL, "used_ip" varchar NULL, "creator" varchar(64) DEFAULT '',