fix(drafts): serialize draft session flushes and register reminders via fds__setReminder
Playwright Tests / test (push) Canceled after 0s
Playwright Tests / test (push) Canceled after 0s
Make invoice/reminder live-draft edits concurrency-safe with an explicit DraftFlushResult, add the fds__setReminder stored procedure, and harden the date helper functions. Includes concurrency and SQL contract tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
d0002ccdad
commit
546648533b
@@ -358,6 +358,7 @@
|
||||
<Build Include="dbo\Stored Procedures\fds__createStorno_simple.sql" />
|
||||
<Build Include="dbo\Stored Procedures\fds__createStorno_copy.sql" />
|
||||
<Build Include="dbo\Stored Procedures\fds__createReminder.sql" />
|
||||
<Build Include="dbo\Stored Procedures\fds__setReminder.sql" />
|
||||
<Build Include="dbo\Stored Procedures\fds__createInvoice_ServiceRequest.sql" />
|
||||
<Build Include="dbo\Stored Procedures\fds__createInvoice_Details.sql" />
|
||||
<Build Include="dbo\Stored Procedures\fds__createInvoice.sql" />
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
CREATE FUNCTION[dbo].[AddBusinessDays](@Date DATE,@n INT)
|
||||
RETURNS DATE AS
|
||||
-- INLINE = OFF: scalar UDF inlining of this @@DATEFIRST arithmetic (reached via date_add /
|
||||
-- date_addcustom) killed dashboard widget queries with error 596 ("session is in the kill state").
|
||||
CREATE FUNCTION[dbo].[AddBusinessDays](@Date DATE,@n INT)
|
||||
RETURNS DATE
|
||||
WITH INLINE = OFF
|
||||
AS
|
||||
BEGIN
|
||||
DECLARE @d INT,@f INT,@DW INT;
|
||||
SET @f=CAST(abs(1^SIGN(DATEPART(DW, @Date)-(7-@@DATEFIRST))) AS BIT)
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
-- Author: <Author,,Name>
|
||||
-- Create date: <Create Date, ,>
|
||||
-- Description: <Description, ,>
|
||||
-- INLINE = OFF: scalar UDF inlining of this IF/nested-UDF body (-> AddBusinessDays)
|
||||
-- killed the dashboard widget queries with error 596 ("session is in the kill
|
||||
-- state", class 21). Called with constant arguments, so per-row cost is negligible.
|
||||
-- =============================================
|
||||
CREATE FUNCTION [dbo].[date_add]
|
||||
(
|
||||
@@ -10,6 +13,7 @@ CREATE FUNCTION [dbo].[date_add]
|
||||
,@shift_to_first bit = 1
|
||||
)
|
||||
RETURNS date
|
||||
WITH INLINE = OFF
|
||||
AS
|
||||
BEGIN
|
||||
DECLARE @Ret date = @date;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
-- Author: <Author,,Name>
|
||||
-- Create date: <Create Date, ,>
|
||||
-- Description: <Description, ,>
|
||||
-- INLINE = OFF: scalar UDF inlining (nested -> AddBusinessDays) killed the dashboard
|
||||
-- widget queries with error 596 ("session is in the kill state", class 21).
|
||||
-- =============================================
|
||||
CREATE FUNCTION [dbo].[date_addcustom]
|
||||
(
|
||||
@@ -9,6 +11,7 @@ CREATE FUNCTION [dbo].[date_addcustom]
|
||||
,@phrase varchar(10)
|
||||
)
|
||||
RETURNS date
|
||||
WITH INLINE = OFF
|
||||
AS
|
||||
BEGIN
|
||||
DECLARE @returndate date, @numpart integer = TRY_PARSE(left(@phrase, patindex('%[^0-9]%', @phrase + '.') - 1) as integer), @defpart varchar(10) = LOWER(RIGHT(@phrase, LEN(@phrase) - patindex('%[^0-9]%', @phrase + '.') + 1));
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
-- =============================================
|
||||
-- Description: Updates an unfinalised reminder draft in place ("Zwischenspeichern" of a draft
|
||||
-- that fds__createReminder already registered) — the reminder counterpart of
|
||||
-- fds__setInvoice. Only a draft that is not finalised and has no stored file is
|
||||
-- touched; otherwise no row is updated, @Id stays NULL and the caller reports the
|
||||
-- save as failed instead of silently doing nothing. The reminder stays bound to its
|
||||
-- invoice: @InvId is not updatable.
|
||||
-- Returns the same single row shape as fds__createReminder.
|
||||
-- =============================================
|
||||
CREATE PROCEDURE [dbo].[fds__setReminder]
|
||||
@RemId varchar(10)
|
||||
, @type varchar(3)
|
||||
, @amount numeric(10,3)
|
||||
, @amount_payed numeric(10,3)
|
||||
, @SendToAddress [nvarchar](1000)
|
||||
, @SendToEmail [nvarchar](255)
|
||||
, @subject nvarchar(255)
|
||||
, @text nvarchar(2000)
|
||||
, @authuser varchar(25)
|
||||
, @Id varchar(10) OUT
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
IF [dbo].[fis_getModuleAuth]('fds_reminder', @authuser) < 2
|
||||
THROW 60000, N'not authorized', 1;
|
||||
|
||||
INSERT INTO [dbo].[fds__admin_activity] ([activity] ,[authuser] ,[info])
|
||||
VALUES ('fds__setReminder' ,@authuser , 'remid: ' + ISNULL(@RemId, ''));
|
||||
|
||||
DECLARE @now datetime = GETUTCDATE();
|
||||
DECLARE @OUT [dbo].[fds__tt__reminder_core];
|
||||
|
||||
UPDATE [dbo].[fds__reminder]
|
||||
SET [Version] = [Version] + 1
|
||||
,[type] = ISNULL(@type, [type])
|
||||
,[amount] = @amount
|
||||
,[amount_payed] = @amount_payed
|
||||
,[SendToAddress] = @SendToAddress
|
||||
,[SendToEmail] = @SendToEmail
|
||||
,[subject] = @subject
|
||||
,[text] = @text
|
||||
,[DateModified] = @now
|
||||
,[UserModified] = @authuser
|
||||
OUTPUT inserted.*
|
||||
INTO @OUT
|
||||
WHERE [Id] = @RemId
|
||||
AND [DateFinalized] IS NULL -- IsFinal = 0
|
||||
AND [file] IS NULL;
|
||||
|
||||
SELECT TOP(1) @Id = [Id] FROM @OUT; -- stays NULL when nothing matched
|
||||
|
||||
With inv as(
|
||||
select TOP(1) * FROM [dbo].[fds__invoices] WHERE [id] = (SELECT TOP(1) [InvId] FROM @OUT)
|
||||
)
|
||||
SELECT TOP(1)
|
||||
o.*
|
||||
, [InvoiceId] = inv.[InvoiceId]
|
||||
, [InvoiceDate] = [dbo].[fds__fn_invoiceDate](inv.[DateFinalized], inv.[DateCreated])
|
||||
, [hasFile] = CAST ( CASE WHEN o.[file] is null THEN 0 ELSE 1 END as bit)
|
||||
, [UserNameFinalized] = [dbo].[fis_admin_getUserName_byID](o.[UserFinalized])
|
||||
, [UserEmailFinalized] = [dbo].[fis_admin_getUserEmail_byID](o.[UserFinalized])
|
||||
from @OUT as o
|
||||
join inv on o.[InvId] = inv.[Id];
|
||||
|
||||
END
|
||||
Reference in New Issue
Block a user