[CLAUDE] PurchaseEvaluation: demo seed 4 phieu + MaPhieu atomic sequence + Pe_* perm defaults
Polish session tiep cua PE module skeleton (commit 2c6f0ca..3990066):
3 task A (MISSING in MVP) khac STATUS.md In Progress:
1. Demo PE data seed (SeedDemoPurchaseEvaluationsAsync)
- 4 phieu varied A/B x phase: A-001 DangSoanThao (mo), A-002
ChoCEODuyetNCC (winner+9 quotes), A-003 DaDuyet (chua tao HD,
PaymentTerms JSON), B-001 ChoDuAn (5-step giua chung).
- Idempotent: skip-if-[DEMO]-exists.
- Approval history dung policy A (3-step) hoac B (5-step).
2. MaPhieu atomic sequence — Migration 13
- Format PE/{YYYY}/{TypeLetter}/{Seq:D3} (vd PE/2026/A/001).
- PurchaseEvaluationCodeSequence entity (Prefix PK).
- IPurchaseEvaluationCodeGenerator + impl SERIALIZABLE
transaction (mirror ContractCodeGenerator 1:1).
- Replace Random.Shared trong CreatePurchaseEvaluationCommandHandler.
- Migration AddPurchaseEvaluationCodeSequences (1 bang).
3. Pe_* permission defaults
- SeedPurchaseEvaluationPermissionDefaultsAsync — 7 role business x 9 menu key.
- Drafter/DeptManager/Procurement: R+C+U; CostControl/PM/Director/AuthorizedSigner: R+U.
- DeptManager them Delete (xoa nhap).
- Idempotent per-(roleId x menuKey).
Build: 0 error, 2 warning (pre-existing DocxRenderer).
Files: 4 new + 8 modified (1 migration + entity + generator + DI + 2 ctx + 2 features).
Resolves: STATUS.md In Progress §A — 3 item PE MISSING.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -0,0 +1,55 @@
|
||||
using System.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SolutionErp.Application.Common.Interfaces;
|
||||
using SolutionErp.Application.PurchaseEvaluations.Services;
|
||||
using SolutionErp.Domain.PurchaseEvaluations;
|
||||
|
||||
namespace SolutionErp.Infrastructure.Services;
|
||||
|
||||
// Mirror ContractCodeGenerator pattern — atomic sequence per (year × type).
|
||||
// Prefix = "PE/{YYYY}/{TypeLetter}".
|
||||
public class PurchaseEvaluationCodeGenerator(IApplicationDbContext db, IDateTime dateTime)
|
||||
: IPurchaseEvaluationCodeGenerator
|
||||
{
|
||||
public async Task<string> GenerateAsync(PurchaseEvaluation evaluation, CancellationToken ct = default)
|
||||
{
|
||||
var typeLetter = evaluation.Type switch
|
||||
{
|
||||
PurchaseEvaluationType.DuyetNcc => "A",
|
||||
PurchaseEvaluationType.DuyetNccPhuongAn => "B",
|
||||
_ => "X",
|
||||
};
|
||||
var year = dateTime.UtcNow.Year;
|
||||
var prefix = $"PE/{year}/{typeLetter}";
|
||||
|
||||
var context = (DbContext)db;
|
||||
await using var tx = await context.Database
|
||||
.BeginTransactionAsync(IsolationLevel.Serializable, ct);
|
||||
try
|
||||
{
|
||||
var seq = await db.PurchaseEvaluationCodeSequences
|
||||
.FirstOrDefaultAsync(s => s.Prefix == prefix, ct);
|
||||
if (seq is null)
|
||||
{
|
||||
seq = new PurchaseEvaluationCodeSequence
|
||||
{
|
||||
Prefix = prefix, LastSeq = 1, UpdatedAt = dateTime.UtcNow,
|
||||
};
|
||||
db.PurchaseEvaluationCodeSequences.Add(seq);
|
||||
}
|
||||
else
|
||||
{
|
||||
seq.LastSeq += 1;
|
||||
seq.UpdatedAt = dateTime.UtcNow;
|
||||
}
|
||||
await db.SaveChangesAsync(ct);
|
||||
await tx.CommitAsync(ct);
|
||||
return $"{prefix}/{seq.LastSeq:D3}";
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user