[CLAUDE] App: golive harden — LeaveBalance concurrency + ItTicket authz-order + DocxRenderer + Travel/Vehicle tests
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m19s

Pre-golive verification (S56) surfaced 4 issues; all fixed + verified (228 test pass, 0 build warning).

#3 LeaveBalance lost-update (DB11 concurrency): terminal-approve deduction was an in-memory read-modify-write (UsedDays += NumDays) under a bare SaveChanges, so two concurrent terminal approvals of the same (user,type,year) lost an update. Fix: atomic server-side ExecuteUpdateAsync (UsedDays = UsedDays + n) inside an explicit Serializable transaction (matches the codegen/Proposal/TravelVehicle convention; serializes the auto-create-row race too). Exactly-once guard (Status != DaGuiDuyet) intact. No migration.

#5 ItTicket reassign existence-oracle: AssignItTicketHandler checked ticket-NotFound before the Admin-OR-dept-IT Forbidden guard. Reordered so authorization runs first -> fail-closed (a non-IT/non-admin caller gets Forbidden for any ticketId, existent or not).

#6 DocxRenderer CS8602: null-guard MainDocumentPart + Document with clear exceptions (cleared 2 build warnings -> 0).

#4 Travel/Vehicle ApproveV2: added smoke tests (Submit->Approve terminal + outsider-Forbidden) — previously zero coverage.

Tests 216 -> 228 (+12). database-agent DB-layer review PASS; em-main cross-stack review clean (reviewer workflow stage did not emit StructuredOutput -> em-main covered the cross-stack review by reading every diff). Bundles agent-memory harvest (S56).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-09 17:51:38 +07:00
parent bef582594e
commit a20cde89fb
13 changed files with 555 additions and 19 deletions

View File

@ -27,17 +27,21 @@ public class DocxRenderer
using (var doc = WordprocessingDocument.Open(ms, isEditable: true))
{
var body = doc.MainDocumentPart?.Document.Body;
var mainPart = doc.MainDocumentPart
?? throw new InvalidOperationException("Template .docx không có MainDocumentPart");
var document = mainPart.Document
?? throw new InvalidOperationException("Template .docx không có Document");
var body = document.Body;
if (body is null) throw new InvalidOperationException("Template .docx không có Body");
// Xử lý cả main document + headers + footers
ReplaceInElement(body, data);
foreach (var hp in doc.MainDocumentPart!.HeaderParts)
foreach (var hp in mainPart.HeaderParts)
if (hp.Header is not null) ReplaceInElement(hp.Header, data);
foreach (var fp in doc.MainDocumentPart.FooterParts)
foreach (var fp in mainPart.FooterParts)
if (fp.Footer is not null) ReplaceInElement(fp.Footer, data);
doc.MainDocumentPart.Document.Save();
document.Save();
}
return new RenderResult(