[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
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:
@ -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(
|
||||
|
||||
Reference in New Issue
Block a user