feat: Enhance invoice file backup procedure to include JSON snapshots
Playwright Tests / test (push) Canceled after 0s
Playwright Tests / test (push) Canceled after 0s
- Updated the stored procedure `fds__admin_backupAndClearInvoiceFile.sql` to back up not only the invoice file but also JSON snapshots of related data (invoices, items, details, service requests) to ensure consistency and traceability. - Modified the table structure of `fds__invoice_file_backups` to accommodate new JSON columns for storing these snapshots. - Added an ADR (0030) document to outline the decision and rationale behind these changes, emphasizing the importance of maintaining a consistent set of data alongside the backed-up file.
This commit is contained in:
@@ -8,7 +8,10 @@
|
||||
-- admin/backupclearinvoicefile action (fds_sys > 4 gate, IntranetController.Admin.cs),
|
||||
-- which logs through the normal ILogger/DB-log-sink pipeline (ADR 0024) instead.
|
||||
--
|
||||
-- Copies the invoice's current [file] bytes into [dbo].[fds__invoice_file_backups],
|
||||
-- Copies the invoice's current [file] bytes into [dbo].[fds__invoice_file_backups]
|
||||
-- together with JSON snapshots of its fds__invoices / fds__invoice_items /
|
||||
-- fds__invoice_details / fds__invoice_servicerequests rows (ADR 0030: file + data
|
||||
-- as one consistent set),
|
||||
-- then clears [file] so the document regenerates on next read (ADR 0025). Both steps
|
||||
-- run in one transaction. Only a finalised, non-external invoice qualifies — the same
|
||||
-- precondition ADR 0025 puts on regeneration: clearing a draft's file would let the
|
||||
@@ -37,11 +40,42 @@ BEGIN
|
||||
BEGIN TRY
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
INSERT INTO [dbo].[fds__invoice_file_backups] ([InvoiceId], [DocumentName], [file], [BackedUpBy])
|
||||
SELECT [Id], [DocumentName], [file], @authuser
|
||||
FROM [dbo].[fds__invoices]
|
||||
WHERE [Id] = @Id AND [file] IS NOT NULL
|
||||
AND [DateFinalized] IS NOT NULL AND ISNULL([IsExternal], 0) = 0;
|
||||
-- The backup row carries the file AND JSON snapshots of the data rows it was rendered from
|
||||
-- (ADR 0030), so a backup is a self-contained, consistent set. The invoice snapshot lists
|
||||
-- its columns explicitly to leave [file] out (it is already stored as bytes in [file] and
|
||||
-- would otherwise be base64-duplicated into the JSON); items, details and service requests take
|
||||
-- every column.
|
||||
INSERT INTO [dbo].[fds__invoice_file_backups]
|
||||
([InvoiceId], [DocumentName], [file], [InvoiceJson], [InvoiceItemsJson], [InvoiceDetailsJson],
|
||||
[InvoiceServiceRequestsJson], [BackedUpBy])
|
||||
SELECT i.[Id], i.[DocumentName], i.[file],
|
||||
(SELECT i.[Id], i.[Version], i.[InvoiceId], i.[InvoiceType], i.[InvoiceTitle], i.[DocumentName],
|
||||
i.[InvoiceBalance], i.[InvoiceBalance_net], i.[InvoiceVAT_net1], i.[InvoiceVAT_1],
|
||||
i.[InvoiceVAT_net2], i.[InvoiceVAT_2], i.[PaymentTerm], i.[DueDate], i.[CustomerId],
|
||||
i.[SendToAddress], i.[SendToEmail], i.[SendToEmailCc], i.[ProvisionPeriod], i.[ProvisionLocation],
|
||||
i.[PaymentStatus], i.[IsPayed], i.[IsSent], i.[IsFinal], i.[IsCanceled], i.[Replaces_InvId],
|
||||
i.[CustomValues], i.[SendToAddressJson], i.[DateSent], i.[UserSent], i.[DateFinalized], i.[UserFinalized],
|
||||
i.[DateCancelled], i.[UserCancelled], i.[DateCreated], i.[UserCreated], i.[DateModified], i.[UserModified],
|
||||
i.[ExternalId], i.[IsExternal], i.[file_guid]
|
||||
FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER),
|
||||
(SELECT it.*
|
||||
FROM [dbo].[fds__invoice_items] it
|
||||
WHERE it.[InvId] = i.[Id]
|
||||
ORDER BY it.[SortOrder], it.[Position], it.[Id]
|
||||
FOR JSON PATH, INCLUDE_NULL_VALUES),
|
||||
(SELECT d.*
|
||||
FROM [dbo].[fds__invoice_details] d
|
||||
WHERE d.[InvId] = i.[Id]
|
||||
FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER),
|
||||
(SELECT sr.*
|
||||
FROM [dbo].[fds__invoice_servicerequests] sr
|
||||
WHERE sr.[InvId] = i.[Id]
|
||||
ORDER BY sr.[SortOrder], sr.[Id]
|
||||
FOR JSON PATH, INCLUDE_NULL_VALUES),
|
||||
@authuser
|
||||
FROM [dbo].[fds__invoices] i
|
||||
WHERE i.[Id] = @Id AND i.[file] IS NOT NULL
|
||||
AND i.[DateFinalized] IS NOT NULL AND ISNULL(i.[IsExternal], 0) = 0;
|
||||
|
||||
UPDATE [dbo].[fds__invoices]
|
||||
SET [file] = NULL
|
||||
|
||||
@@ -3,6 +3,15 @@ CREATE TABLE [dbo].[fds__invoice_file_backups] (
|
||||
[InvoiceId] VARCHAR (10) NOT NULL,
|
||||
[DocumentName] VARCHAR (50) NULL,
|
||||
[file] VARBINARY (MAX) NOT NULL,
|
||||
-- JSON snapshots (FOR JSON PATH) of the invoice's data rows at backup time, so the file and
|
||||
-- the data it was rendered from stay together as one consistent set (ADR 0030).
|
||||
-- InvoiceJson: the fds__invoices row without [file]; InvoiceItemsJson: array of
|
||||
-- fds__invoice_items rows; InvoiceDetailsJson: the fds__invoice_details row (NULL if none);
|
||||
-- InvoiceServiceRequestsJson: array of fds__invoice_servicerequests rows.
|
||||
[InvoiceJson] NVARCHAR (MAX) NULL,
|
||||
[InvoiceItemsJson] NVARCHAR (MAX) NULL,
|
||||
[InvoiceDetailsJson] NVARCHAR (MAX) NULL,
|
||||
[InvoiceServiceRequestsJson] NVARCHAR (MAX) NULL,
|
||||
[BackedUpAt] DATETIME CONSTRAINT [DF_fds__invoice_file_backups_BackedUpAt] DEFAULT (getutcdate()) NOT NULL,
|
||||
[BackedUpBy] VARCHAR (25) NULL,
|
||||
CONSTRAINT [PK_fds__invoice_file_backups] PRIMARY KEY CLUSTERED ([uid] ASC)
|
||||
|
||||
Reference in New Issue
Block a user