/* Customer-specific review draft for the lserp_AI compatibility-level-100 database. This file is intentionally inert. SET NOEXEC ON prevents the definition from being applied and @customer_dba_reviewed remains 0. purchase.open_sources contains a bounded candidate query only so that its field, permission and allocation contract can be compiled and reviewed without enabling it. The customer DBA must create a separate approved deployment script after reviewing the database, account-book, subsystem, permission, status, currency, row-scope, calendar and source-allocation rules. Do not edit this evidence draft in place. Payload parsing happens in the trusted ERP process. This procedure accepts only fixed, typed scalar parameters and therefore does not depend on JSON functions unavailable at database compatibility level 100. */ SET NOEXEC ON; GO CREATE PROCEDURE dbo.p_lserp_agent_workflow_read_compat100 @workflow VARCHAR(32), @action VARCHAR(64), @module_code NVARCHAR(64), @account_book NVARCHAR(64), @subsystem_id NVARCHAR(32), @user_id NVARCHAR(64), @reference NVARCHAR(500) = NULL, @tax_id NVARCHAR(50) = NULL, @line_id NVARCHAR(64) = NULL, @specification NVARCHAR(200) = NULL, @unit NVARCHAR(100) = NULL, @supplier_code NVARCHAR(64) = NULL, @currency_code NVARCHAR(64) = NULL, @invoice_number NVARCHAR(128) = NULL, @query NVARCHAR(500) = NULL, @employee_id NVARCHAR(64) = NULL, @local_date NVARCHAR(10) = NULL, @day_part VARCHAR(16) = NULL, @leave_type_code NVARCHAR(64) = NULL, @flow_type_query NVARCHAR(500) = NULL, @calculated_hours DECIMAL(18, 6) = NULL, @flow_type_code NVARCHAR(64) = NULL, @start_local DATETIME = NULL, @end_local DATETIME = NULL, @record_id NVARCHAR(128) = NULL AS BEGIN SET NOCOUNT ON; DECLARE @customer_dba_reviewed BIT; SET @customer_dba_reviewed = 0; IF DB_NAME() <> N'lserp_AI' BEGIN RAISERROR(N'workflow_database_not_allowed', 16, 1); RETURN; END; IF NULLIF(LTRIM(RTRIM(@account_book)), N'') IS NULL OR NULLIF(LTRIM(RTRIM(@user_id)), N'') IS NULL BEGIN RAISERROR(N'workflow_context_invalid', 16, 1); RETURN; END; IF @workflow = 'purchase' BEGIN IF @module_code <> N'acc_1007' OR @subsystem_id <> N'5' BEGIN RAISERROR(N'purchase_scope_not_allowed', 16, 1); RETURN; END; IF @action NOT IN ('resolve_supplier', 'resolve_currency', 'resolve_material', 'invoice_exists', 'open_sources') BEGIN RAISERROR(N'purchase_action_not_allowed', 16, 1); RETURN; END; END ELSE IF @workflow = 'leave' BEGIN IF @module_code <> N'hr_4011' OR @subsystem_id <> N'7' BEGIN RAISERROR(N'leave_scope_not_allowed', 16, 1); RETURN; END; IF @action NOT IN ('context', 'resolve_type', 'resolve_flow_type', 'resolve_calendar_range', 'type_enabled', 'flow_type_enabled', 'calculate_hours', 'has_conflict', 'can_submit') BEGIN RAISERROR(N'leave_action_not_allowed', 16, 1); RETURN; END; END ELSE BEGIN RAISERROR(N'workflow_not_allowed', 16, 1); RETURN; END; IF @customer_dba_reviewed <> 1 BEGIN RAISERROR(N'customer_dba_review_required', 16, 1); RETURN; END; IF LEN(@user_id) > 10 OR @user_id LIKE N'%[^0-9]%' BEGIN RAISERROR(N'erp_employee_context_invalid', 16, 1); RETURN; END; DECLARE @user_number DECIMAL(10, 0); SET @user_number = CONVERT(DECIMAL(10, 0), @user_id); IF @user_number < 1 OR @user_number > 2147483647 BEGIN RAISERROR(N'erp_employee_context_invalid', 16, 1); RETURN; END; DECLARE @current_employee_id INT; DECLARE @current_employee_name NVARCHAR(50); DECLARE @current_department_id INT; SET @current_employee_id = CONVERT(INT, @user_number); SELECT @current_employee_name = CONVERT(NVARCHAR(50), EmployeeName), @current_department_id = Departmentid FROM dbo.p_employeetab WHERE employeeid = @current_employee_id AND ISNULL(p_emp_status, '') <> N'离职'; IF @current_employee_name IS NULL BEGIN RAISERROR(N'erp_employee_context_invalid', 16, 1); RETURN; END; DECLARE @permission_text NVARCHAR(MAX); SET @permission_text = N','; SELECT TOP (1) @permission_text = N',' + CONVERT(NVARCHAR(MAX), ISNULL(wmsPurview, '')) + N',' + ISNULL(KcPurview, '') + N',' + ISNULL(crmPurview, '') + N',' + ISNULL(bomPurview, '') + N',' + ISNULL(mpsPurview, '') + N',' + ISNULL(mrpPurview, '') + N',' + ISNULL(scmPurview, '') + N',' + ISNULL(sellPurview, '') + N',' + ISNULL(RdmPurview, '') + N',' + ISNULL(hrPurview, '') + N',' + ISNULL(costPurview, '') + N',' + ISNULL(eamPurview, '') + N',' + ISNULL(accPurview, '') + N',' + ISNULL(oaPurview, '') + N',' + ISNULL(BiPurview, '') + N',' + ISNULL(QmsPurview, '') + N',' + ISNULL(FmPurview, '') + N',' + ISNULL(Ppurview, '') + N',' + ISNULL(EMApurview, '') + N',' + ISNULL(GYSpurview, '') + N',' + ISNULL(PdaPurview, '') + N',' + ISNULL(GFPTPurview, '') + N',' + ISNULL(scmtestPurview, '') + N',' + ISNULL(CBpurview, '') + N',' + ISNULL(PMPurview, '') + N',' + ISNULL(SMSPurview, '') + N',' + ISNULL(AMSPurview, '') + N',' + ISNULL(cmspurview, '') + N',' + ISNULL(MEspurview, '') + N',' + ISNULL(APSPurview, '') + N',' + ISNULL(KFpurview, '') + N',' + ISNULL(qmcPurview, '') + N',' FROM dbo.p_SubsysPurviewTab WHERE employeeid = @current_employee_id; DECLARE @required_menu_id INT; SET @required_menu_id = CASE WHEN @workflow = 'purchase' THEN 18848 ELSE 16629 END; IF (@current_employee_id <> 1 OR @current_employee_name <> N'管理员') AND CHARINDEX(N',' + CONVERT(NVARCHAR(20), @required_menu_id) + N',', @permission_text) = 0 AND CHARINDEX(N',' + CONVERT(NVARCHAR(20), @required_menu_id) + N'|,', @permission_text) = 0 BEGIN RAISERROR(N'workflow_module_permission_denied', 16, 1); RETURN; END; IF @workflow = 'purchase' AND @action = 'resolve_supplier' BEGIN SET @reference = NULLIF(LTRIM(RTRIM(@reference)), N''); SET @tax_id = NULLIF(LTRIM(RTRIM(@tax_id)), N''); IF @reference IS NULL AND @tax_id IS NULL BEGIN RAISERROR(N'purchase_supplier_reference_required', 16, 1); RETURN; END; IF ( SELECT COUNT_BIG(*) FROM dbo.p_providertab WHERE ISNULL(IsDisabled, 0) = 0 AND ISNULL(ban, 0) = 0 AND ISNULL(cancelFlag, 0) = 0 AND ( @reference IS NULL OR CONVERT(NVARCHAR(32), id) = @reference OR CONVERT(NVARCHAR(20), Coid) = @reference OR CONVERT(NVARCHAR(100), CoCode) = @reference OR CONVERT(NVARCHAR(500), CoName) = @reference OR CONVERT(NVARCHAR(500), CoAlias) = @reference ) AND (@tax_id IS NULL OR CONVERT(NVARCHAR(50), taxid) = @tax_id) ) > 20 BEGIN RAISERROR(N'purchase_supplier_candidates_exceeded', 16, 1); RETURN; END; SELECT CONVERT(NVARCHAR(32), id) AS supplier_code, CONVERT(NVARCHAR(500), CoName) AS supplier_name, CONVERT(NVARCHAR(50), taxid) AS supplier_tax_id FROM dbo.p_providertab WHERE ISNULL(IsDisabled, 0) = 0 AND ISNULL(ban, 0) = 0 AND ISNULL(cancelFlag, 0) = 0 AND ( @reference IS NULL OR CONVERT(NVARCHAR(32), id) = @reference OR CONVERT(NVARCHAR(20), Coid) = @reference OR CONVERT(NVARCHAR(100), CoCode) = @reference OR CONVERT(NVARCHAR(500), CoName) = @reference OR CONVERT(NVARCHAR(500), CoAlias) = @reference ) AND (@tax_id IS NULL OR CONVERT(NVARCHAR(50), taxid) = @tax_id) ORDER BY id; RETURN; END; IF @workflow = 'purchase' AND @action = 'resolve_currency' BEGIN SET @reference = NULLIF(LTRIM(RTRIM(@reference)), N''); IF @reference IS NULL OR LEN(@reference) > 40 BEGIN RAISERROR(N'purchase_currency_reference_invalid', 16, 1); RETURN; END; /* Purchase orders and acc_1007 use different currency dictionaries. Never expose a source currency to matching unless finance/DBA has approved its exact target mapping. OCR may supply either dictionary's exact id, code or name, but the result deliberately remains the source P_CurrencyType id used by open_sources and by the signed write wrapper. */ IF OBJECT_ID(N'dbo.p_agent_purchase_currency_crosswalk', N'U') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_currency_crosswalk', N'source_currency_id') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_currency_crosswalk', N'target_currency_id') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_currency_crosswalk', N'is_active') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_currency_crosswalk', N'approval_evidence_sha256') IS NULL OR NOT EXISTS ( SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'dbo.p_agent_purchase_currency_crosswalk') AND name = N'UX_p_agent_purchase_currency_active' AND is_unique = 1 AND has_filter = 1 AND is_disabled = 0 ) BEGIN RAISERROR(N'purchase_agent_evidence_schema_missing', 16, 1); RETURN; END; IF NOT EXISTS ( SELECT 1 FROM dbo.P_CurrencyType AS known_source_currency WHERE ISNULL(known_source_currency.is_active, 1) = 1 AND ( CONVERT(NVARCHAR(32), known_source_currency.id) = @reference OR CONVERT(NVARCHAR(3), known_source_currency.currency_code) = @reference OR known_source_currency.currency_name = @reference ) ) AND NOT EXISTS ( SELECT 1 FROM dbo.P_BaseMixInfoTab AS known_target_currency WHERE known_target_currency.Tag = 'L000101' AND ISNULL(known_target_currency.Ban, 0) = 0 AND ISNULL(known_target_currency.Delid, 0) = 0 AND ( CONVERT(NVARCHAR(32), known_target_currency.ID) = @reference OR CONVERT(NVARCHAR(100), known_target_currency.Mix_NO) = @reference OR CONVERT(NVARCHAR(500), known_target_currency.Mix_apellation) = @reference ) ) BEGIN /* Unknown references remain an empty candidate set so the trusted ERP adapter can return purchase_currency_not_resolved without disclosing dictionary contents. */ SELECT CONVERT(NVARCHAR(32), NULL) AS currency_code, CONVERT(NVARCHAR(40), NULL) AS currency_name WHERE 1 = 0; RETURN; END; IF NOT EXISTS ( SELECT 1 FROM dbo.P_CurrencyType AS approved_source_currency INNER JOIN dbo.p_agent_purchase_currency_crosswalk AS approved_mapping ON approved_mapping.source_currency_id = approved_source_currency.id INNER JOIN dbo.P_BaseMixInfoTab AS approved_target_currency ON approved_target_currency.ID = approved_mapping.target_currency_id AND approved_target_currency.Tag = 'L000101' WHERE approved_mapping.is_active = 1 AND LEN(approved_mapping.approval_evidence_sha256) = 64 AND approved_mapping.approval_evidence_sha256 COLLATE Latin1_General_100_BIN2 NOT LIKE '%[^0-9a-f]%' AND 1 = ( SELECT COUNT_BIG(*) FROM dbo.p_agent_purchase_currency_crosswalk AS source_mapping_count WHERE source_mapping_count.source_currency_id = approved_source_currency.id AND source_mapping_count.is_active = 1 AND LEN(source_mapping_count.approval_evidence_sha256) = 64 AND source_mapping_count.approval_evidence_sha256 COLLATE Latin1_General_100_BIN2 NOT LIKE '%[^0-9a-f]%' ) AND ISNULL(approved_source_currency.is_active, 1) = 1 AND ISNULL(approved_target_currency.Ban, 0) = 0 AND ISNULL(approved_target_currency.Delid, 0) = 0 AND ( CONVERT(NVARCHAR(32), approved_source_currency.id) = @reference OR CONVERT(NVARCHAR(3), approved_source_currency.currency_code) = @reference OR approved_source_currency.currency_name = @reference OR CONVERT(NVARCHAR(32), approved_target_currency.ID) = @reference OR CONVERT(NVARCHAR(100), approved_target_currency.Mix_NO) = @reference OR CONVERT(NVARCHAR(500), approved_target_currency.Mix_apellation) = @reference ) ) BEGIN RAISERROR(N'purchase_currency_crosswalk_not_approved', 16, 1); RETURN; END; IF ( SELECT COUNT_BIG(*) FROM ( SELECT approved_source_currency.id FROM dbo.P_CurrencyType AS approved_source_currency INNER JOIN dbo.p_agent_purchase_currency_crosswalk AS approved_mapping ON approved_mapping.source_currency_id = approved_source_currency.id INNER JOIN dbo.P_BaseMixInfoTab AS approved_target_currency ON approved_target_currency.ID = approved_mapping.target_currency_id AND approved_target_currency.Tag = 'L000101' WHERE approved_mapping.is_active = 1 AND LEN(approved_mapping.approval_evidence_sha256) = 64 AND approved_mapping.approval_evidence_sha256 COLLATE Latin1_General_100_BIN2 NOT LIKE '%[^0-9a-f]%' AND 1 = ( SELECT COUNT_BIG(*) FROM dbo.p_agent_purchase_currency_crosswalk AS source_mapping_count WHERE source_mapping_count.source_currency_id = approved_source_currency.id AND source_mapping_count.is_active = 1 AND LEN(source_mapping_count.approval_evidence_sha256) = 64 AND source_mapping_count.approval_evidence_sha256 COLLATE Latin1_General_100_BIN2 NOT LIKE '%[^0-9a-f]%' ) AND ISNULL(approved_source_currency.is_active, 1) = 1 AND ISNULL(approved_target_currency.Ban, 0) = 0 AND ISNULL(approved_target_currency.Delid, 0) = 0 AND ( CONVERT(NVARCHAR(32), approved_source_currency.id) = @reference OR CONVERT(NVARCHAR(3), approved_source_currency.currency_code) = @reference OR approved_source_currency.currency_name = @reference OR CONVERT(NVARCHAR(32), approved_target_currency.ID) = @reference OR CONVERT(NVARCHAR(100), approved_target_currency.Mix_NO) = @reference OR CONVERT(NVARCHAR(500), approved_target_currency.Mix_apellation) = @reference ) GROUP BY approved_source_currency.id ) AS approved_currency_candidates ) > 20 BEGIN RAISERROR(N'purchase_currency_candidates_exceeded', 16, 1); RETURN; END; SELECT CONVERT(NVARCHAR(32), approved_source_currency.id) AS currency_code, CONVERT(NVARCHAR(40), approved_source_currency.currency_name) AS currency_name FROM dbo.P_CurrencyType AS approved_source_currency INNER JOIN dbo.p_agent_purchase_currency_crosswalk AS approved_mapping ON approved_mapping.source_currency_id = approved_source_currency.id INNER JOIN dbo.P_BaseMixInfoTab AS approved_target_currency ON approved_target_currency.ID = approved_mapping.target_currency_id AND approved_target_currency.Tag = 'L000101' WHERE approved_mapping.is_active = 1 AND LEN(approved_mapping.approval_evidence_sha256) = 64 AND approved_mapping.approval_evidence_sha256 COLLATE Latin1_General_100_BIN2 NOT LIKE '%[^0-9a-f]%' AND 1 = ( SELECT COUNT_BIG(*) FROM dbo.p_agent_purchase_currency_crosswalk AS source_mapping_count WHERE source_mapping_count.source_currency_id = approved_source_currency.id AND source_mapping_count.is_active = 1 AND LEN(source_mapping_count.approval_evidence_sha256) = 64 AND source_mapping_count.approval_evidence_sha256 COLLATE Latin1_General_100_BIN2 NOT LIKE '%[^0-9a-f]%' ) AND ISNULL(approved_source_currency.is_active, 1) = 1 AND ISNULL(approved_target_currency.Ban, 0) = 0 AND ISNULL(approved_target_currency.Delid, 0) = 0 AND ( CONVERT(NVARCHAR(32), approved_source_currency.id) = @reference OR CONVERT(NVARCHAR(3), approved_source_currency.currency_code) = @reference OR approved_source_currency.currency_name = @reference OR CONVERT(NVARCHAR(32), approved_target_currency.ID) = @reference OR CONVERT(NVARCHAR(100), approved_target_currency.Mix_NO) = @reference OR CONVERT(NVARCHAR(500), approved_target_currency.Mix_apellation) = @reference ) GROUP BY approved_source_currency.id, approved_source_currency.currency_name ORDER BY approved_source_currency.id; RETURN; END; IF @workflow = 'purchase' AND @action = 'resolve_material' BEGIN SET @reference = NULLIF(LTRIM(RTRIM(@reference)), N''); SET @specification = NULLIF(LTRIM(RTRIM(@specification)), N''); SET @unit = NULLIF(LTRIM(RTRIM(@unit)), N''); SET @supplier_code = NULLIF(LTRIM(RTRIM(@supplier_code)), N''); IF @reference IS NULL OR @supplier_code IS NULL OR LEN(@supplier_code) > 10 OR @supplier_code LIKE N'%[^0-9]%' BEGIN RAISERROR(N'purchase_material_reference_invalid', 16, 1); RETURN; END; DECLARE @material_supplier_number DECIMAL(10, 0); DECLARE @material_supplier_id INT; SET @material_supplier_number = CONVERT(DECIMAL(10, 0), @supplier_code); IF @material_supplier_number < 1 OR @material_supplier_number > 2147483647 BEGIN RAISERROR(N'purchase_material_reference_invalid', 16, 1); RETURN; END; SET @material_supplier_id = CONVERT(INT, @material_supplier_number); IF ( SELECT COUNT_BIG(*) FROM dbo.P_productTab WHERE ISNULL(delid, 0) = 0 AND ISNULL(IsLocked, 0) = 0 AND ISNULL(IsDisabled, 0) = 0 AND ISNULL(ban, 0) = 0 AND ISNULL(cancelFlag, 0) = 0 AND ( CONVERT(NVARCHAR(32), id) = @reference OR CONVERT(NVARCHAR(200), productid) = @reference OR CONVERT(NVARCHAR(500), appellation) = @reference ) AND ( @specification IS NULL OR CONVERT(NVARCHAR(200), spec) = @specification OR CONVERT(NVARCHAR(200), model) = @specification ) AND ( @unit IS NULL OR CONVERT(NVARCHAR(20), productunitname) = @unit OR CONVERT(NVARCHAR(100), pur_unit) = @unit ) AND (pur_providerid IS NULL OR pur_providerid = @material_supplier_id) ) > 20 BEGIN RAISERROR(N'purchase_material_candidates_exceeded', 16, 1); RETURN; END; SELECT CONVERT(NVARCHAR(200), productid) AS material_code, CONVERT(NVARCHAR(500), appellation) AS material_name, CONVERT(NVARCHAR(200), COALESCE(NULLIF(spec, ''), model, '')) AS specification, CONVERT(NVARCHAR(100), COALESCE(NULLIF(productunitname, ''), pur_unit, '')) AS unit FROM dbo.P_productTab WHERE ISNULL(delid, 0) = 0 AND ISNULL(IsLocked, 0) = 0 AND ISNULL(IsDisabled, 0) = 0 AND ISNULL(ban, 0) = 0 AND ISNULL(cancelFlag, 0) = 0 AND ( CONVERT(NVARCHAR(32), id) = @reference OR CONVERT(NVARCHAR(200), productid) = @reference OR CONVERT(NVARCHAR(500), appellation) = @reference ) AND ( @specification IS NULL OR CONVERT(NVARCHAR(200), spec) = @specification OR CONVERT(NVARCHAR(200), model) = @specification ) AND ( @unit IS NULL OR CONVERT(NVARCHAR(20), productunitname) = @unit OR CONVERT(NVARCHAR(100), pur_unit) = @unit ) AND (pur_providerid IS NULL OR pur_providerid = @material_supplier_id) ORDER BY productid; RETURN; END; IF @workflow = 'purchase' AND @action = 'invoice_exists' BEGIN SET @supplier_code = NULLIF(LTRIM(RTRIM(@supplier_code)), N''); SET @invoice_number = NULLIF(LTRIM(RTRIM(@invoice_number)), N''); IF @supplier_code IS NULL OR @invoice_number IS NULL OR LEN(@supplier_code) > 10 OR @supplier_code LIKE N'%[^0-9]%' BEGIN RAISERROR(N'purchase_invoice_identity_invalid', 16, 1); RETURN; END; DECLARE @invoice_supplier_number DECIMAL(10, 0); DECLARE @invoice_supplier_id INT; SET @invoice_supplier_number = CONVERT(DECIMAL(10, 0), @supplier_code); IF @invoice_supplier_number < 1 OR @invoice_supplier_number > 2147483647 BEGIN RAISERROR(N'purchase_invoice_identity_invalid', 16, 1); RETURN; END; SET @invoice_supplier_id = CONVERT(INT, @invoice_supplier_number); SELECT CONVERT(BIT, CASE WHEN EXISTS ( SELECT 1 FROM dbo.ACC_billscmInvoicemainPIDHxtab WHERE acc_mphhscm_Providerid = @invoice_supplier_id AND CONVERT(NVARCHAR(MAX), acc_mphhscm_invoice) = @invoice_number AND ISNULL(acc_mphhscm_cancelFlag, 0) = 0 AND ISNULL(acc_mphhscm_wasteoper, 0) = 0 ) OR EXISTS ( SELECT 1 FROM dbo.ACC_billscminvoicemaintab WHERE acc_mscmi_Providerid = @invoice_supplier_id AND CONVERT(NVARCHAR(50), acc_mscmi_invoice) = @invoice_number AND ISNULL(acc_mscmi_cancelFlag, 0) = 0 AND ISNULL(acc_mscmi_wasteoper, 0) = 0 ) THEN 1 ELSE 0 END) AS [exists]; RETURN; END; IF @workflow = 'purchase' AND @action = 'open_sources' BEGIN SET @supplier_code = NULLIF(LTRIM(RTRIM(@supplier_code)), N''); SET @currency_code = NULLIF(LTRIM(RTRIM(@currency_code)), N''); IF @supplier_code IS NULL OR @currency_code IS NULL OR LEN(@supplier_code) > 10 OR @supplier_code LIKE N'%[^0-9]%' OR LEN(@currency_code) > 10 OR @currency_code LIKE N'%[^0-9]%' BEGIN RAISERROR(N'purchase_source_identity_invalid', 16, 1); RETURN; END; DECLARE @source_supplier_number DECIMAL(10, 0); DECLARE @source_currency_number DECIMAL(10, 0); DECLARE @source_supplier_id INT; DECLARE @source_currency_id INT; SET @source_supplier_number = CONVERT(DECIMAL(10, 0), @supplier_code); SET @source_currency_number = CONVERT(DECIMAL(10, 0), @currency_code); IF @source_supplier_number < 1 OR @source_supplier_number > 2147483647 OR @source_currency_number < 1 OR @source_currency_number > 2147483647 BEGIN RAISERROR(N'purchase_source_identity_invalid', 16, 1); RETURN; END; SET @source_supplier_id = CONVERT(INT, @source_supplier_number); SET @source_currency_id = CONVERT(INT, @source_currency_number); IF NOT EXISTS ( SELECT 1 FROM dbo.P_CurrencyType WHERE id = @source_currency_id ) BEGIN RAISERROR(N'purchase_source_currency_invalid', 16, 1); RETURN; END; /* Reading purchase-order rows requires the PUR_5001 menu in addition to the acc_1007 permission checked above. Every returned row must also match one currently active, signed procurement scope tuple; administrators do not bypass this data boundary. */ IF (@current_employee_id <> 1 OR @current_employee_name <> N'管理员') AND CHARINDEX(N',187,', @permission_text) = 0 AND CHARINDEX(N',187|,', @permission_text) = 0 BEGIN RAISERROR(N'purchase_source_permission_denied', 16, 1); RETURN; END; IF OBJECT_ID(N'dbo.p_agent_purchase_row_scope', N'U') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'account_book') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'subsystem_id') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'erp_user_id') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'group_id') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'department_id') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'purchase_user_id') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'is_active') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'approval_evidence_sha256') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'valid_from_utc') IS NULL OR COL_LENGTH(N'dbo.p_agent_purchase_row_scope', N'valid_to_utc') IS NULL OR NOT EXISTS ( SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(N'dbo.p_agent_purchase_row_scope') AND name = N'UX_p_agent_purchase_row_scope_active' AND is_unique = 1 AND has_filter = 1 AND is_disabled = 0 ) BEGIN RAISERROR(N'purchase_agent_evidence_schema_missing', 16, 1); RETURN; END; IF NOT EXISTS ( SELECT 1 FROM dbo.p_agent_purchase_row_scope WHERE account_book = @account_book AND subsystem_id = @subsystem_id AND erp_user_id = @user_id AND is_active = 1 AND valid_from_utc <= SYSUTCDATETIME() AND (valid_to_utc IS NULL OR valid_to_utc > SYSUTCDATETIME()) AND LEN(approval_evidence_sha256) = 64 AND approval_evidence_sha256 COLLATE Latin1_General_100_BIN2 NOT LIKE '%[^0-9a-f]%' ) BEGIN RAISERROR(N'purchase_row_scope_denied', 16, 1); RETURN; END; ;WITH active_invoice_quantity AS ( SELECT invoice_line.acc_lphhscm_ScmPoid AS source_line_id, SUM(ISNULL(invoice_line.acc_lphhscm_amount, 0)) AS reserved_quantity FROM dbo.ACC_billscmInvoicelistPIDHxtab AS invoice_line INNER JOIN dbo.ACC_billscmInvoicemainPIDHxtab AS invoice_main ON invoice_main.acc_mphhscm_billdocument_id = invoice_line.acc_lphhscm_billdocument_id WHERE invoice_line.acc_lphhscm_ScmPoid IS NOT NULL AND ISNULL(invoice_main.acc_mphhscm_cancelFlag, 0) = 0 AND ISNULL(invoice_main.acc_mphhscm_wasteoper, 0) = 0 AND ISNULL(invoice_main.acc_mphhscm_delid, 0) = 0 GROUP BY invoice_line.acc_lphhscm_ScmPoid ), source_candidates AS ( SELECT order_line.scm_lpo_Billdocument_id, order_main.scm_mpo_handcraftId, order_line.scm_lpo_id, order_main.scm_mpo_Providerid, order_main.scm_mpo_Currency, order_line.scm_lpo_Productid, order_line.scm_lpo_ProductUnitName, CONVERT(DECIMAL(19, 8), ISNULL(order_line.scm_lpo_Amount, 0) - ISNULL(reserved.reserved_quantity, 0)) AS remaining_quantity, CONVERT(DECIMAL(19, 12), ISNULL(order_line.scm_lpo_Fprice, 0)) AS unit_price, CONVERT(DECIMAL(19, 8), ISNULL(order_line.scm_lpo_taxRate, 0)) AS tax_rate, CONVERT(DECIMAL(19, 8), COALESCE( NULLIF(order_line.scm_lpo_ExchangeRate, 0), order_main.scm_mpo_ExchangeRate, 0)) AS exchange_rate FROM dbo.scm_BillPolistTab AS order_line INNER JOIN dbo.scm_BillPoMainTab AS order_main ON order_main.scm_mpo_Billdocument_Id = order_line.scm_lpo_Billdocument_id LEFT JOIN active_invoice_quantity AS reserved ON reserved.source_line_id = order_line.scm_lpo_id WHERE order_main.scm_mpo_Providerid = @source_supplier_id AND LTRIM(RTRIM(CONVERT(NVARCHAR(20), order_main.scm_mpo_Currency))) = CONVERT(NVARCHAR(20), @source_currency_id) AND ISNULL(order_main.scm_mpo_stepover, 0) = 1 AND ISNULL(order_main.scm_mpo_cancelFlag, 0) = 0 AND ISNULL(order_main.scm_mpo_wasteoper, 0) = 0 AND ISNULL(order_main.scm_mpo_ban, 0) = 0 AND EXISTS ( SELECT 1 FROM dbo.p_agent_purchase_row_scope AS allowed_scope WHERE allowed_scope.account_book = @account_book AND allowed_scope.subsystem_id = @subsystem_id AND allowed_scope.erp_user_id = @user_id AND CONVERT(NVARCHAR(20), allowed_scope.group_id) = LTRIM(RTRIM(CONVERT(NVARCHAR(20), order_main.scm_mpo_Groupid))) AND CONVERT(NVARCHAR(20), allowed_scope.department_id) = LTRIM(RTRIM(CONVERT(NVARCHAR(20), order_main.scm_mpo_Departmentid))) AND CONVERT(NVARCHAR(20), allowed_scope.purchase_user_id) = LTRIM(RTRIM(CONVERT(NVARCHAR(20), order_main.scm_mpo_PurchaseUserId))) AND allowed_scope.is_active = 1 AND allowed_scope.valid_from_utc <= SYSUTCDATETIME() AND (allowed_scope.valid_to_utc IS NULL OR allowed_scope.valid_to_utc > SYSUTCDATETIME()) AND LEN(allowed_scope.approval_evidence_sha256) = 64 AND allowed_scope.approval_evidence_sha256 COLLATE Latin1_General_100_BIN2 NOT LIKE '%[^0-9a-f]%' ) ) SELECT TOP (10001) CONVERT(NVARCHAR(50), scm_lpo_Billdocument_id) AS source_order_id, CONVERT(NVARCHAR(50), COALESCE( NULLIF(LTRIM(RTRIM(scm_mpo_handcraftId)), ''), scm_lpo_Billdocument_id)) AS source_order_number, CONVERT(NVARCHAR(32), scm_lpo_id) AS source_line_id, CONVERT(NVARCHAR(32), scm_mpo_Providerid) AS supplier_code, CONVERT(NVARCHAR(32), @source_currency_id) AS currency_code, CONVERT(NVARCHAR(200), scm_lpo_Productid) AS material_code, CONVERT(NVARCHAR(100), scm_lpo_ProductUnitName) AS unit, remaining_quantity, unit_price, tax_rate, exchange_rate, CONVERT(BIT, 0) AS closed FROM source_candidates WHERE remaining_quantity > 0 ORDER BY scm_lpo_Billdocument_id, scm_lpo_id; RETURN; END; IF @workflow = 'leave' AND @action = 'context' BEGIN SELECT CONVERT(NVARCHAR(32), @current_employee_id) AS current_employee_id, CONVERT(BIT, 0) AS can_apply_for_others, CONVERT(DATETIME, DATEADD(HOUR, 8, SYSUTCDATETIME())) AS now_local; RETURN; END; IF @workflow = 'leave' AND @action = 'resolve_type' BEGIN SET @query = NULLIF(LTRIM(RTRIM(@query)), N''); IF @query IS NULL BEGIN RAISERROR(N'leave_type_query_invalid', 16, 1); RETURN; END; ;WITH leave_types AS ( SELECT CONVERT(NVARCHAR(64), 1) AS leave_type_code, CONVERT(NVARCHAR(128), CONVERT(NVARCHAR(4), YEAR(GETDATE())) + N'年假剩余' + CONVERT(NVARCHAR(30), ISNULL(p_emp_holidaybalance, 0)) + N'小时') AS leave_type_name, CONVERT(NVARCHAR(64), N'本年年假') AS alias_one, CONVERT(NVARCHAR(64), N'年假') AS alias_two FROM dbo.p_employeetab WHERE employeeid = @current_employee_id UNION ALL SELECT CONVERT(NVARCHAR(64), 2), CONVERT(NVARCHAR(128), CONVERT(NVARCHAR(4), YEAR(GETDATE()) - 1) + N'年假剩余' + CONVERT(NVARCHAR(30), ISNULL(p_emp_lastholidaybalance, 0)) + N'小时'), CONVERT(NVARCHAR(64), N'上年年假'), CONVERT(NVARCHAR(64), N'年假') FROM dbo.p_employeetab WHERE employeeid = @current_employee_id UNION ALL SELECT CONVERT(NVARCHAR(64), 3), CONVERT(NVARCHAR(128), CONVERT(NVARCHAR(4), YEAR(GETDATE())) + N'年调休剩余' + CONVERT(NVARCHAR(30), ISNULL(p_emp_txholidaybalance, 0)) + N'小时'), CONVERT(NVARCHAR(64), N'本年调休'), CONVERT(NVARCHAR(64), N'调休') FROM dbo.p_employeetab WHERE employeeid = @current_employee_id UNION ALL SELECT CONVERT(NVARCHAR(64), 4), CONVERT(NVARCHAR(128), CONVERT(NVARCHAR(4), YEAR(GETDATE()) - 1) + N'年调休剩余' + CONVERT(NVARCHAR(30), ISNULL(p_emp_lasttxholidaybalance, 0)) + N'小时'), CONVERT(NVARCHAR(64), N'上年调休'), CONVERT(NVARCHAR(64), N'调休') FROM dbo.p_employeetab WHERE employeeid = @current_employee_id UNION ALL SELECT CONVERT(NVARCHAR(64), ID), CONVERT(NVARCHAR(128), Mix_apellation), CONVERT(NVARCHAR(64), Mix_NO), CONVERT(NVARCHAR(64), Mix_apellation) FROM dbo.P_BaseMixInfoTab WHERE Tag = '7001801' AND Ban = 0 AND ID NOT IN (1, 2, 3, 4) ) SELECT leave_type_code, leave_type_name FROM leave_types WHERE @query IN (leave_type_code, leave_type_name, alias_one, alias_two) ORDER BY CONVERT(INT, leave_type_code), leave_type_code; RETURN; END; IF @workflow = 'leave' AND @action = 'type_enabled' BEGIN SET @leave_type_code = NULLIF(LTRIM(RTRIM(@leave_type_code)), N''); IF @leave_type_code IS NULL OR LEN(@leave_type_code) > 10 OR @leave_type_code LIKE N'%[^0-9]%' BEGIN SELECT CONVERT(BIT, 0) AS enabled; RETURN; END; DECLARE @leave_type_number DECIMAL(10, 0); DECLARE @leave_type_id INT; SET @leave_type_number = CONVERT(DECIMAL(10, 0), @leave_type_code); IF @leave_type_number < 1 OR @leave_type_number > 2147483647 BEGIN SELECT CONVERT(BIT, 0) AS enabled; RETURN; END; SET @leave_type_id = CONVERT(INT, @leave_type_number); SELECT CONVERT(BIT, CASE WHEN @leave_type_id IN (1, 2, 3, 4) OR EXISTS ( SELECT 1 FROM dbo.P_BaseMixInfoTab WHERE ID = @leave_type_id AND Tag = '7001801' AND Ban = 0 ) THEN 1 ELSE 0 END) AS enabled; RETURN; END; IF @workflow = 'leave' AND @action = 'resolve_flow_type' BEGIN SET @employee_id = NULLIF(LTRIM(RTRIM(@employee_id)), N''); SET @flow_type_query = NULLIF(LTRIM(RTRIM(@flow_type_query)), N''); IF @employee_id IS NULL OR LEN(@employee_id) > 10 OR @employee_id LIKE N'%[^0-9]%' OR @calculated_hours IS NULL OR @calculated_hours <= 0 OR @calculated_hours > 744 BEGIN RAISERROR(N'leave_flow_type_request_invalid', 16, 1); RETURN; END; DECLARE @flow_employee_number DECIMAL(10, 0); SET @flow_employee_number = CONVERT(DECIMAL(10, 0), @employee_id); IF @flow_employee_number <> @current_employee_id BEGIN RAISERROR(N'leave_flow_type_request_invalid', 16, 1); RETURN; END; IF ( SELECT COUNT_BIG(*) FROM dbo.p_systemdlltabflowtype AS flow_type WHERE flow_type.typeCode = 'hr_4011' AND ISNULL(flow_type.billflowban, 0) = 0 AND EXISTS ( SELECT 1 FROM dbo.p_systemdlltabflowtypestep AS flow_step WHERE flow_step.typeCode = 'hr_4011' AND flow_step.billType = CONVERT(VARCHAR(10), flow_type.id) AND ISNULL(flow_step.stepClosed, 0) = 0 ) AND ( @flow_type_query IS NULL OR CONVERT(NVARCHAR(64), flow_type.id) = @flow_type_query OR CONVERT(NVARCHAR(128), flow_type.billTypeName) = @flow_type_query ) ) > 20 BEGIN RAISERROR(N'leave_flow_type_candidates_exceeded', 16, 1); RETURN; END; /* calculated_hours is deliberately not used to infer an approval route. The customer has multiple rank/day categories but no reviewed deterministic employee-rank mapping. An empty query therefore returns every enabled choice. */ SELECT CONVERT(NVARCHAR(64), flow_type.id) AS flow_type_code, CONVERT(NVARCHAR(128), flow_type.billTypeName) AS flow_type_name FROM dbo.p_systemdlltabflowtype AS flow_type WHERE flow_type.typeCode = 'hr_4011' AND ISNULL(flow_type.billflowban, 0) = 0 AND EXISTS ( SELECT 1 FROM dbo.p_systemdlltabflowtypestep AS flow_step WHERE flow_step.typeCode = 'hr_4011' AND flow_step.billType = CONVERT(VARCHAR(10), flow_type.id) AND ISNULL(flow_step.stepClosed, 0) = 0 ) AND ( @flow_type_query IS NULL OR CONVERT(NVARCHAR(64), flow_type.id) = @flow_type_query OR CONVERT(NVARCHAR(128), flow_type.billTypeName) = @flow_type_query ) ORDER BY flow_type.id; RETURN; END; IF @workflow = 'leave' AND @action = 'flow_type_enabled' BEGIN SET @flow_type_code = NULLIF(LTRIM(RTRIM(@flow_type_code)), N''); IF @flow_type_code IS NULL OR LEN(@flow_type_code) > 10 OR @flow_type_code LIKE N'%[^0-9]%' BEGIN SELECT CONVERT(BIT, 0) AS enabled; RETURN; END; SELECT CONVERT(BIT, CASE WHEN EXISTS ( SELECT 1 FROM dbo.p_systemdlltabflowtype WHERE CONVERT(NVARCHAR(64), id) = @flow_type_code AND typeCode = 'hr_4011' AND ISNULL(billflowban, 0) = 0 AND EXISTS ( SELECT 1 FROM dbo.p_systemdlltabflowtypestep WHERE typeCode = 'hr_4011' AND billType = @flow_type_code AND ISNULL(stepClosed, 0) = 0 ) ) THEN 1 ELSE 0 END) AS enabled; RETURN; END; IF @workflow = 'leave' AND @action = 'resolve_calendar_range' BEGIN SET @employee_id = NULLIF(LTRIM(RTRIM(@employee_id)), N''); IF @employee_id IS NULL OR LEN(@employee_id) > 10 OR @employee_id LIKE N'%[^0-9]%' OR @local_date IS NULL OR LEN(@local_date) <> 10 OR SUBSTRING(@local_date, 5, 1) <> N'-' OR SUBSTRING(@local_date, 8, 1) <> N'-' OR STUFF(STUFF(@local_date, 8, 1, N''), 5, 1, N'') LIKE N'%[^0-9]%' OR ISDATE(@local_date) <> 1 OR @day_part NOT IN ('morning', 'afternoon', 'full_day') BEGIN RAISERROR(N'leave_calendar_request_invalid', 16, 1); RETURN; END; DECLARE @calendar_employee_number DECIMAL(10, 0); DECLARE @calendar_employee_id INT; DECLARE @calendar_date DATE; SET @calendar_employee_number = CONVERT(DECIMAL(10, 0), @employee_id); IF @calendar_employee_number <> @current_employee_id BEGIN RAISERROR(N'leave_calendar_request_invalid', 16, 1); RETURN; END; SET @calendar_employee_id = CONVERT(INT, @calendar_employee_number); SET @calendar_date = CONVERT(DATE, @local_date, 23); DECLARE @schedule_count BIGINT; SELECT @schedule_count = COUNT_BIG(*) FROM dbo.HR_ScheduleTab WHERE HR_Schedule_employeeid = @calendar_employee_id AND HR_Schedule_Date = @calendar_date; IF @schedule_count = 0 BEGIN SELECT CONVERT(BIT, 0) AS available, CONVERT(VARCHAR(64), 'schedule_missing') AS reason_code, CONVERT(DATETIME, NULL) AS start_local, CONVERT(DATETIME, NULL) AS end_local, CONVERT(DECIMAL(18, 4), NULL) AS hours, CONVERT(NVARCHAR(128), NULL) AS time_zone_id; RETURN; END; IF @schedule_count <> 1 BEGIN RAISERROR(N'leave_calendar_duplicate_schedule', 16, 1); RETURN; END; DECLARE @is_workday INT; DECLARE @am_start_raw DATETIME; DECLARE @am_end_raw DATETIME; DECLARE @pm_start_raw DATETIME; DECLARE @pm_end_raw DATETIME; SELECT @is_workday = HR_Schedule_IsWorkday, @am_start_raw = HR_Schedule_AMStartTime, @am_end_raw = HR_Schedule_AMEndTime, @pm_start_raw = HR_Schedule_PMStartTime, @pm_end_raw = HR_Schedule_PMEndTime FROM dbo.HR_ScheduleTab WHERE HR_Schedule_employeeid = @calendar_employee_id AND HR_Schedule_Date = @calendar_date; IF ISNULL(@is_workday, 0) <> 1 BEGIN SELECT CONVERT(BIT, 0) AS available, CONVERT(VARCHAR(64), 'not_workday') AS reason_code, CONVERT(DATETIME, NULL) AS start_local, CONVERT(DATETIME, NULL) AS end_local, CONVERT(DECIMAL(18, 4), NULL) AS hours, CONVERT(NVARCHAR(128), NULL) AS time_zone_id; RETURN; END; IF @am_start_raw IS NULL OR @am_end_raw IS NULL OR @pm_start_raw IS NULL OR @pm_end_raw IS NULL BEGIN RAISERROR(N'leave_calendar_shift_invalid', 16, 1); RETURN; END; DECLARE @am_start DATETIME; DECLARE @am_end DATETIME; DECLARE @pm_start DATETIME; DECLARE @pm_end DATETIME; SET @am_start = DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, CONVERT(DATE, @am_start_raw), @am_start_raw), CONVERT(DATETIME, @calendar_date)); SET @am_end = DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, CONVERT(DATE, @am_end_raw), @am_end_raw), CONVERT(DATETIME, @calendar_date)); SET @pm_start = DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, CONVERT(DATE, @pm_start_raw), @pm_start_raw), CONVERT(DATETIME, @calendar_date)); SET @pm_end = DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, CONVERT(DATE, @pm_end_raw), @pm_end_raw), CONVERT(DATETIME, @calendar_date)); IF @am_start >= @am_end OR @pm_start >= @pm_end OR @am_end > @pm_start BEGIN RAISERROR(N'leave_calendar_shift_invalid', 16, 1); RETURN; END; DECLARE @range_start DATETIME; DECLARE @range_end DATETIME; DECLARE @range_seconds BIGINT; SET @range_start = CASE WHEN @day_part = 'afternoon' THEN @pm_start ELSE @am_start END; SET @range_end = CASE WHEN @day_part = 'morning' THEN @am_end ELSE @pm_end END; SET @range_seconds = CASE WHEN @day_part = 'morning' THEN DATEDIFF(SECOND, @am_start, @am_end) WHEN @day_part = 'afternoon' THEN DATEDIFF(SECOND, @pm_start, @pm_end) ELSE DATEDIFF(SECOND, @am_start, @am_end) + DATEDIFF(SECOND, @pm_start, @pm_end) END; SELECT CONVERT(BIT, 1) AS available, CONVERT(VARCHAR(64), 'ok') AS reason_code, @range_start AS start_local, @range_end AS end_local, CONVERT(DECIMAL(18, 4), @range_seconds / 3600.0) AS hours, CONVERT(NVARCHAR(128), N'China Standard Time') AS time_zone_id; RETURN; END; IF @workflow = 'leave' AND @action IN ('calculate_hours', 'has_conflict') BEGIN SET @employee_id = NULLIF(LTRIM(RTRIM(@employee_id)), N''); IF @employee_id IS NULL OR LEN(@employee_id) > 10 OR @employee_id LIKE N'%[^0-9]%' OR @start_local IS NULL OR @end_local IS NULL OR @end_local <= @start_local OR DATEDIFF(DAY, CONVERT(DATE, @start_local), CONVERT(DATE, @end_local)) > 366 BEGIN RAISERROR(N'leave_time_range_invalid', 16, 1); RETURN; END; DECLARE @time_employee_number DECIMAL(10, 0); DECLARE @time_employee_id INT; SET @time_employee_number = CONVERT(DECIMAL(10, 0), @employee_id); IF @time_employee_number <> @current_employee_id BEGIN RAISERROR(N'leave_time_range_invalid', 16, 1); RETURN; END; SET @time_employee_id = CONVERT(INT, @time_employee_number); IF @action = 'has_conflict' BEGIN SELECT CONVERT(BIT, CASE WHEN EXISTS ( SELECT 1 FROM dbo.HR_EmpLeaveAloneTab WHERE hr_ela_empid = @time_employee_id AND hr_ela_starttime < @end_local AND hr_ela_finishtime > @start_local AND ISNULL(hr_ela_cancelFlag, 0) = 0 ) THEN 1 ELSE 0 END) AS has_conflict; RETURN; END; IF EXISTS ( SELECT 1 FROM ( SELECT TOP (DATEDIFF(DAY, CONVERT(DATE, @start_local), CONVERT(DATE, @end_local)) + 1) DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1, CONVERT(DATE, @start_local)) AS work_date FROM sys.all_objects ) AS requested_dates WHERE NOT EXISTS ( SELECT 1 FROM dbo.HR_ScheduleTab WHERE HR_Schedule_employeeid = @time_employee_id AND HR_Schedule_Date = requested_dates.work_date ) ) BEGIN RAISERROR(N'leave_calendar_schedule_missing', 16, 1); RETURN; END; IF EXISTS ( SELECT HR_Schedule_Date FROM dbo.HR_ScheduleTab WHERE HR_Schedule_employeeid = @time_employee_id AND HR_Schedule_Date BETWEEN CONVERT(DATE, @start_local) AND CONVERT(DATE, @end_local) GROUP BY HR_Schedule_Date HAVING COUNT_BIG(*) <> 1 ) BEGIN RAISERROR(N'leave_calendar_schedule_duplicate', 16, 1); RETURN; END; IF EXISTS ( SELECT 1 FROM dbo.HR_ScheduleTab WHERE HR_Schedule_employeeid = @time_employee_id AND HR_Schedule_Date BETWEEN CONVERT(DATE, @start_local) AND CONVERT(DATE, @end_local) AND ISNULL(HR_Schedule_IsWorkday, 0) = 1 AND ( HR_Schedule_AMStartTime IS NULL OR HR_Schedule_AMEndTime IS NULL OR HR_Schedule_PMStartTime IS NULL OR HR_Schedule_PMEndTime IS NULL OR CONVERT(TIME, HR_Schedule_AMStartTime) >= CONVERT(TIME, HR_Schedule_AMEndTime) OR CONVERT(TIME, HR_Schedule_PMStartTime) >= CONVERT(TIME, HR_Schedule_PMEndTime) OR CONVERT(TIME, HR_Schedule_AMEndTime) > CONVERT(TIME, HR_Schedule_PMStartTime) ) ) BEGIN RAISERROR(N'leave_calendar_shift_invalid', 16, 1); RETURN; END; ;WITH schedule_days AS ( SELECT HR_Schedule_Date AS work_date, HR_Schedule_AMStartTime AS am_start_raw, HR_Schedule_AMEndTime AS am_end_raw, HR_Schedule_PMStartTime AS pm_start_raw, HR_Schedule_PMEndTime AS pm_end_raw FROM dbo.HR_ScheduleTab WHERE HR_Schedule_employeeid = @time_employee_id AND HR_Schedule_Date BETWEEN CONVERT(DATE, @start_local) AND CONVERT(DATE, @end_local) AND ISNULL(HR_Schedule_IsWorkday, 0) = 1 ), work_segments AS ( SELECT DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, CONVERT(DATE, am_start_raw), am_start_raw), CONVERT(DATETIME, work_date)) AS segment_start, DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, CONVERT(DATE, am_end_raw), am_end_raw), CONVERT(DATETIME, work_date)) AS segment_end FROM schedule_days UNION ALL SELECT DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, CONVERT(DATE, pm_start_raw), pm_start_raw), CONVERT(DATETIME, work_date)), DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, CONVERT(DATE, pm_end_raw), pm_end_raw), CONVERT(DATETIME, work_date)) FROM schedule_days ), overlaps AS ( SELECT CASE WHEN @start_local > segment_start THEN @start_local ELSE segment_start END AS overlap_start, CASE WHEN @end_local < segment_end THEN @end_local ELSE segment_end END AS overlap_end FROM work_segments WHERE segment_start < segment_end AND @start_local < segment_end AND @end_local > segment_start ) SELECT CONVERT(DECIMAL(18, 4), ISNULL(SUM(CASE WHEN overlap_start < overlap_end THEN DATEDIFF(SECOND, overlap_start, overlap_end) ELSE 0 END), 0) / 3600.0) AS hours FROM overlaps; RETURN; END; IF @workflow = 'leave' AND @action = 'can_submit' BEGIN SET @record_id = NULLIF(LTRIM(RTRIM(@record_id)), N''); IF @record_id IS NULL BEGIN RAISERROR(N'leave_record_id_invalid', 16, 1); RETURN; END; IF ( SELECT COUNT_BIG(*) FROM dbo.HR_EmpLeaveAloneTab WHERE CONVERT(NVARCHAR(32), hr_ela_id) = @record_id OR CONVERT(NVARCHAR(50), hr_ela_no) = @record_id ) > 1 BEGIN RAISERROR(N'leave_record_identity_ambiguous', 16, 1); RETURN; END; DECLARE @record_employee_id INT; DECLARE @record_operator_id INT; DECLARE @record_affirmer INT; DECLARE @record_ban INT; DECLARE @record_stepover INT; DECLARE @record_cancel INT; DECLARE @record_stepdirection CHAR(1); DECLARE @record_start DATETIME; DECLARE @record_end DATETIME; DECLARE @record_hours FLOAT; SELECT @record_employee_id = hr_ela_empid, @record_operator_id = hr_ela_operatorid, @record_affirmer = hr_ela_Affirmer, @record_ban = hr_ela_ban, @record_stepover = hr_ela_stepover, @record_cancel = hr_ela_cancelFlag, @record_stepdirection = hr_ela_stepdirection, @record_start = hr_ela_starttime, @record_end = hr_ela_finishtime, @record_hours = hr_ela_totals FROM dbo.HR_EmpLeaveAloneTab WHERE CONVERT(NVARCHAR(32), hr_ela_id) = @record_id OR CONVERT(NVARCHAR(50), hr_ela_no) = @record_id; DECLARE @can_submit BIT; DECLARE @submit_reason NVARCHAR(128); SET @can_submit = 1; SET @submit_reason = N'ok'; IF @record_employee_id IS NULL BEGIN SET @can_submit = 0; SET @submit_reason = N'record_not_found'; END ELSE IF @record_employee_id <> @current_employee_id AND ISNULL(@record_operator_id, -1) <> @current_employee_id AND (@current_employee_id <> 1 OR @current_employee_name <> N'管理员') AND ISNULL(@current_department_id, -1) <> 1 BEGIN SET @can_submit = 0; SET @submit_reason = N'record_owner_mismatch'; END ELSE IF ISNULL(@record_cancel, 0) <> 0 BEGIN SET @can_submit = 0; SET @submit_reason = N'record_cancelled'; END ELSE IF ISNULL(@record_affirmer, 0) <> 0 OR ISNULL(@record_stepover, 0) <> 0 OR ISNULL(@record_ban, 0) <> 0 OR ISNULL(@record_stepdirection, '') <> '' BEGIN SET @can_submit = 0; SET @submit_reason = N'record_workflow_locked'; END ELSE IF @record_start IS NULL OR @record_end IS NULL OR @record_end <= @record_start OR ISNULL(@record_hours, 0) <= 0 BEGIN SET @can_submit = 0; SET @submit_reason = N'record_content_invalid'; END; SELECT @can_submit AS can_submit, @submit_reason AS reason; RETURN; END; RAISERROR(N'workflow_action_not_implemented', 16, 1); RETURN; END; GO