[CLAUDE] PurchaseEvaluation: User chọn quy trình duyệt V2 lúc tạo phiếu (Mig 23)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
User feedback: thay field "Loại quy trình (theo menu — khóa)" disabled
→ Select dropdown cho User pick quy trình ApprovalWorkflowsV2 (Mig 22)
ngay từ workspace tạo mới. Hiển thị "Mã + Tên + Version".
BE Domain:
- PurchaseEvaluation +ApprovalWorkflowId Guid? (nullable, FK Restrict)
- EF Configuration: Index + FK Restrict to ApprovalWorkflows
- Migration 23 `AddApprovalWorkflowIdToPurchaseEvaluation` (1 ALTER +
1 IX + 1 FK), applied cả _Design + _Dev LocalDB
- Field WorkflowDefinitionId (Mig 21 legacy) giữ song song để Service
PE chạy logic cũ tới khi Session sau wire qua schema mới
BE Application:
- CreatePurchaseEvaluationCommand +ApprovalWorkflowId? Guid? optional
param (default null)
- Validate: nếu set, phải tồn tại + ApplicableType khớp PE.Type
(DuyetNcc=1 → ApprovalWorkflowApplicableType.DuyetNcc, etc)
- Handler set entity.ApprovalWorkflowId từ request
- UpdatePurchaseEvaluationDraftCommand mirror — cho User đổi quy trình
khi sửa Nháp/Trả lại (validate same)
- PurchaseEvaluationDetailBundleDto +ApprovalWorkflowId/Code/Name/Version
- GetPurchaseEvaluationByIdQuery handler load workflow info join
- Update Phase guard: cho sửa cả DangSoanThao + TraLai (Trả lại =
editable per Session 17 spec)
FE (cả 2 app mirror):
- types/purchaseEvaluation.ts: PeDetail +approvalWorkflowId/Code/Name/Version
- PeWorkspaceCreateView.tsx:
- Replace field disabled "Loại quy trình" → Select bắt buộc
- useQuery `/api/approval-workflows-v2?applicableType=N` filter theo
defaultType (1=DuyetNcc / 2=DuyetNccPhuongAn)
- Display option: "QT-DN-V2-001 v01 — Quy trình Duyệt NCC (đang áp dụng)"
- List cả version active + archived (UAT cần test compare)
- Empty state hint amber "Chưa có quy trình, vào /system/approval-workflows-v2"
- canSubmit require approvalWorkflowId set
- POST payload include approvalWorkflowId
Verify: dotnet build OK · 81 test pass · npm build × 2 OK · Mig 23 applied
cả 2 LocalDB.
Logic Service PE chưa wire qua ApprovalWorkflowId — vẫn pin
WorkflowDefinitionId Mig 21 legacy chạy. Session sau wire Service iterate
ApprovalWorkflowSteps + match approver theo schema V2 + drop legacy.
This commit is contained in:
@ -59,6 +59,8 @@ export function PeWorkspaceCreateView({
|
||||
budgetManual: false,
|
||||
budgetManualName: '',
|
||||
budgetManualAmount: 0,
|
||||
// Mig 23 — Pin quy trình duyệt V2 (User tự chọn lúc tạo)
|
||||
approvalWorkflowId: '',
|
||||
})
|
||||
// Payment terms: select preset OR "Khác" → text input
|
||||
const [paymentMode, setPaymentMode] = useState<string>('') // '' / preset / __custom__
|
||||
@ -69,6 +71,22 @@ export function PeWorkspaceCreateView({
|
||||
queryFn: async () => (await api.get<{ items: Project[] }>('/projects', { params: { pageSize: 1000 } })).data.items,
|
||||
})
|
||||
|
||||
// Mig 23 — fetch list quy trình duyệt V2 cho User chọn (filter theo
|
||||
// ApplicableType khớp với defaultType: 1=DuyetNcc / 2=DuyetNccPhuongAn).
|
||||
const approvalWorkflows = useQuery({
|
||||
queryKey: ['approval-workflows-v2-active', defaultType],
|
||||
queryFn: async () => {
|
||||
const res = await api.get<{ types: { applicableType: number; history: { id: string; code: string; version: number; name: string; isActive: boolean }[] }[] }>(
|
||||
'/approval-workflows-v2',
|
||||
{ params: { applicableType: defaultType } },
|
||||
)
|
||||
// Trả về tất cả version (active + archived) cho User pick — UAT cần
|
||||
// flexibility chọn cả version cũ test compare.
|
||||
const typeBucket = res.data.types.find(t => t.applicableType === defaultType)
|
||||
return typeBucket?.history ?? []
|
||||
},
|
||||
})
|
||||
|
||||
const eligibleBudgets = useQuery({
|
||||
queryKey: ['eligible-budgets', form.projectId],
|
||||
queryFn: async () => {
|
||||
@ -93,6 +111,7 @@ export function PeWorkspaceCreateView({
|
||||
diaDiem: form.diaDiem || null,
|
||||
moTa: form.moTa || null,
|
||||
paymentTerms: form.paymentTerms || null,
|
||||
approvalWorkflowId: form.approvalWorkflowId || null,
|
||||
...budgetPayload,
|
||||
})
|
||||
return res.data.id
|
||||
@ -105,7 +124,7 @@ export function PeWorkspaceCreateView({
|
||||
onError: e => toast.error(getErrorMessage(e)),
|
||||
})
|
||||
|
||||
const canSubmit = !!form.tenGoiThau && !!form.projectId && !create.isPending
|
||||
const canSubmit = !!form.tenGoiThau && !!form.projectId && !!form.approvalWorkflowId && !create.isPending
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-slate-200 bg-white shadow-sm">
|
||||
@ -126,15 +145,31 @@ export function PeWorkspaceCreateView({
|
||||
{/* Section 1 — Thông tin gói thầu (editable) */}
|
||||
<Section title="1. Thông tin gói thầu">
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
<div>
|
||||
<Label className="text-[11px]">Loại quy trình (theo menu — khóa)</Label>
|
||||
<Input
|
||||
value={PurchaseEvaluationTypeLabel[form.type]}
|
||||
disabled
|
||||
className="bg-slate-100 font-medium"
|
||||
/>
|
||||
<div className="md:col-span-2">
|
||||
<Label className="text-[11px]">
|
||||
Quy trình duyệt * <span className="text-[10px] font-normal text-slate-400">(theo {PurchaseEvaluationTypeLabel[form.type]})</span>
|
||||
</Label>
|
||||
<Select
|
||||
value={form.approvalWorkflowId}
|
||||
onChange={e => setForm({ ...form, approvalWorkflowId: e.target.value })}
|
||||
required
|
||||
>
|
||||
<option value="">— Chọn quy trình duyệt —</option>
|
||||
{approvalWorkflows.data?.map(w => (
|
||||
<option key={w.id} value={w.id}>
|
||||
{w.code} v{String(w.version).padStart(2, '0')} — {w.name}
|
||||
{w.isActive ? ' (đang áp dụng)' : ''}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
{approvalWorkflows.data && approvalWorkflows.data.length === 0 && (
|
||||
<p className="mt-1 text-[11px] text-amber-700">
|
||||
⚠ Chưa có quy trình duyệt cho loại {PurchaseEvaluationTypeLabel[form.type]}. Vào{' '}
|
||||
<span className="font-mono">/system/approval-workflows-v2</span> để tạo trước.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="md:col-span-1">
|
||||
<div className="md:col-span-2">
|
||||
<Label className="text-[11px]">a. Tên gói thầu *</Label>
|
||||
<Input
|
||||
value={form.tenGoiThau}
|
||||
|
||||
@ -310,6 +310,11 @@ export type PeDetailBundle = {
|
||||
// Mig 17 — manual budget fallback khi không link Budget entity. Cả 2 cùng null OK.
|
||||
budgetManualName: string | null
|
||||
budgetManualAmount: number | null
|
||||
// Mig 23 — Pin schema mới ApprovalWorkflowsV2 (User chọn lúc create).
|
||||
approvalWorkflowId: string | null
|
||||
approvalWorkflowCode: string | null
|
||||
approvalWorkflowName: string | null
|
||||
approvalWorkflowVersion: number | null
|
||||
suppliers: PeSupplier[]
|
||||
details: PeDetailRow[]
|
||||
approvals: PeApproval[]
|
||||
|
||||
@ -59,6 +59,8 @@ export function PeWorkspaceCreateView({
|
||||
budgetManual: false,
|
||||
budgetManualName: '',
|
||||
budgetManualAmount: 0,
|
||||
// Mig 23 — Pin quy trình duyệt V2 (User tự chọn lúc tạo)
|
||||
approvalWorkflowId: '',
|
||||
})
|
||||
// Payment terms: select preset OR "Khác" → text input
|
||||
const [paymentMode, setPaymentMode] = useState<string>('') // '' / preset / __custom__
|
||||
@ -69,6 +71,19 @@ export function PeWorkspaceCreateView({
|
||||
queryFn: async () => (await api.get<{ items: Project[] }>('/projects', { params: { pageSize: 1000 } })).data.items,
|
||||
})
|
||||
|
||||
// Mig 23 — fetch list quy trình duyệt V2 (filter ApplicableType khớp defaultType).
|
||||
const approvalWorkflows = useQuery({
|
||||
queryKey: ['approval-workflows-v2-active', defaultType],
|
||||
queryFn: async () => {
|
||||
const res = await api.get<{ types: { applicableType: number; history: { id: string; code: string; version: number; name: string; isActive: boolean }[] }[] }>(
|
||||
'/approval-workflows-v2',
|
||||
{ params: { applicableType: defaultType } },
|
||||
)
|
||||
const typeBucket = res.data.types.find(t => t.applicableType === defaultType)
|
||||
return typeBucket?.history ?? []
|
||||
},
|
||||
})
|
||||
|
||||
const eligibleBudgets = useQuery({
|
||||
queryKey: ['eligible-budgets', form.projectId],
|
||||
queryFn: async () => {
|
||||
@ -93,6 +108,7 @@ export function PeWorkspaceCreateView({
|
||||
diaDiem: form.diaDiem || null,
|
||||
moTa: form.moTa || null,
|
||||
paymentTerms: form.paymentTerms || null,
|
||||
approvalWorkflowId: form.approvalWorkflowId || null,
|
||||
...budgetPayload,
|
||||
})
|
||||
return res.data.id
|
||||
@ -105,7 +121,7 @@ export function PeWorkspaceCreateView({
|
||||
onError: e => toast.error(getErrorMessage(e)),
|
||||
})
|
||||
|
||||
const canSubmit = !!form.tenGoiThau && !!form.projectId && !create.isPending
|
||||
const canSubmit = !!form.tenGoiThau && !!form.projectId && !!form.approvalWorkflowId && !create.isPending
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-slate-200 bg-white shadow-sm">
|
||||
@ -126,15 +142,30 @@ export function PeWorkspaceCreateView({
|
||||
{/* Section 1 — Thông tin gói thầu (editable) */}
|
||||
<Section title="1. Thông tin gói thầu">
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
<div>
|
||||
<Label className="text-[11px]">Loại quy trình (theo menu — khóa)</Label>
|
||||
<Input
|
||||
value={PurchaseEvaluationTypeLabel[form.type]}
|
||||
disabled
|
||||
className="bg-slate-100 font-medium"
|
||||
/>
|
||||
<div className="md:col-span-2">
|
||||
<Label className="text-[11px]">
|
||||
Quy trình duyệt * <span className="text-[10px] font-normal text-slate-400">(theo {PurchaseEvaluationTypeLabel[form.type]})</span>
|
||||
</Label>
|
||||
<Select
|
||||
value={form.approvalWorkflowId}
|
||||
onChange={e => setForm({ ...form, approvalWorkflowId: e.target.value })}
|
||||
required
|
||||
>
|
||||
<option value="">— Chọn quy trình duyệt —</option>
|
||||
{approvalWorkflows.data?.map(w => (
|
||||
<option key={w.id} value={w.id}>
|
||||
{w.code} v{String(w.version).padStart(2, '0')} — {w.name}
|
||||
{w.isActive ? ' (đang áp dụng)' : ''}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
{approvalWorkflows.data && approvalWorkflows.data.length === 0 && (
|
||||
<p className="mt-1 text-[11px] text-amber-700">
|
||||
⚠ Chưa có quy trình duyệt cho loại {PurchaseEvaluationTypeLabel[form.type]}. Liên hệ admin tạo trước.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="md:col-span-1">
|
||||
<div className="md:col-span-2">
|
||||
<Label className="text-[11px]">a. Tên gói thầu *</Label>
|
||||
<Input
|
||||
value={form.tenGoiThau}
|
||||
|
||||
@ -309,6 +309,11 @@ export type PeDetailBundle = {
|
||||
// Mig 17 — manual budget fallback khi không link Budget entity. Cả 2 cùng null OK.
|
||||
budgetManualName: string | null
|
||||
budgetManualAmount: number | null
|
||||
// Mig 23 — Pin schema mới ApprovalWorkflowsV2 (User chọn lúc create).
|
||||
approvalWorkflowId: string | null
|
||||
approvalWorkflowCode: string | null
|
||||
approvalWorkflowName: string | null
|
||||
approvalWorkflowVersion: number | null
|
||||
suppliers: PeSupplier[]
|
||||
details: PeDetailRow[]
|
||||
approvals: PeApproval[]
|
||||
|
||||
@ -129,6 +129,12 @@ public record PurchaseEvaluationDetailBundleDto(
|
||||
BudgetSummaryDto? Budget,
|
||||
string? BudgetManualName,
|
||||
decimal? BudgetManualAmount,
|
||||
// Mig 23 — schema mới ApprovalWorkflowsV2 pin lúc create. Hiển thị Code +
|
||||
// Name + Version để FE show "QT-DN-V2-001 - Quy trình Duyệt NCC (v01)".
|
||||
Guid? ApprovalWorkflowId,
|
||||
string? ApprovalWorkflowCode,
|
||||
string? ApprovalWorkflowName,
|
||||
int? ApprovalWorkflowVersion,
|
||||
List<PurchaseEvaluationSupplierDto> Suppliers,
|
||||
List<PurchaseEvaluationDetailDto> Details,
|
||||
List<PurchaseEvaluationApprovalDto> Approvals,
|
||||
|
||||
@ -25,7 +25,8 @@ public record CreatePurchaseEvaluationCommand(
|
||||
string? PaymentTerms,
|
||||
Guid? BudgetId,
|
||||
string? BudgetManualName,
|
||||
decimal? BudgetManualAmount) : IRequest<Guid>;
|
||||
decimal? BudgetManualAmount,
|
||||
Guid? ApprovalWorkflowId = null) : IRequest<Guid>; // [Mig 23] User chọn quy trình duyệt V2 lúc tạo
|
||||
|
||||
public class CreatePurchaseEvaluationCommandValidator : AbstractValidator<CreatePurchaseEvaluationCommand>
|
||||
{
|
||||
@ -57,6 +58,23 @@ public class CreatePurchaseEvaluationCommandHandler(
|
||||
.Select(w => (Guid?)w.Id)
|
||||
.FirstOrDefaultAsync(ct);
|
||||
|
||||
// Validate ApprovalWorkflowId V2 (Mig 23) — User chọn lúc create.
|
||||
// Phải tồn tại + ApplicableType khớp với PE.Type.
|
||||
if (request.ApprovalWorkflowId is Guid awId)
|
||||
{
|
||||
var aw = await db.ApprovalWorkflows.AsNoTracking()
|
||||
.FirstOrDefaultAsync(w => w.Id == awId, ct)
|
||||
?? throw new NotFoundException("ApprovalWorkflow", awId);
|
||||
var expectedType = request.Type switch
|
||||
{
|
||||
PurchaseEvaluationType.DuyetNcc => Domain.ApprovalWorkflowsV2.ApprovalWorkflowApplicableType.DuyetNcc,
|
||||
PurchaseEvaluationType.DuyetNccPhuongAn => Domain.ApprovalWorkflowsV2.ApprovalWorkflowApplicableType.DuyetNccPhuongAn,
|
||||
_ => throw new ConflictException($"PurchaseEvaluationType {request.Type} chưa map sang ApprovalWorkflowApplicableType."),
|
||||
};
|
||||
if (aw.ApplicableType != expectedType)
|
||||
throw new ConflictException($"Quy trình {aw.Code} áp dụng cho {aw.ApplicableType}, không khớp với loại phiếu {request.Type}.");
|
||||
}
|
||||
|
||||
// Validate Budget link (nếu có): cùng Project + Phase=DaDuyet (chỉ cho
|
||||
// pick ngân sách đã duyệt mới được dùng làm reference đối chiếu).
|
||||
if (request.BudgetId is Guid bid)
|
||||
@ -81,6 +99,7 @@ public class CreatePurchaseEvaluationCommandHandler(
|
||||
MoTa = request.MoTa,
|
||||
DrafterUserId = currentUser.UserId,
|
||||
WorkflowDefinitionId = activeWfId,
|
||||
ApprovalWorkflowId = request.ApprovalWorkflowId, // Mig 23 — schema mới V2
|
||||
PaymentTerms = request.PaymentTerms,
|
||||
BudgetId = request.BudgetId,
|
||||
BudgetManualName = request.BudgetManualName,
|
||||
@ -120,7 +139,8 @@ public record UpdatePurchaseEvaluationDraftCommand(
|
||||
string? PaymentTerms,
|
||||
Guid? BudgetId,
|
||||
string? BudgetManualName,
|
||||
decimal? BudgetManualAmount) : IRequest;
|
||||
decimal? BudgetManualAmount,
|
||||
Guid? ApprovalWorkflowId = null) : IRequest; // [Mig 23] cho User đổi quy trình khi sửa Nháp
|
||||
|
||||
public class UpdatePurchaseEvaluationDraftCommandHandler(
|
||||
IApplicationDbContext db,
|
||||
@ -131,8 +151,25 @@ public class UpdatePurchaseEvaluationDraftCommandHandler(
|
||||
var entity = await db.PurchaseEvaluations.FirstOrDefaultAsync(x => x.Id == request.Id, ct)
|
||||
?? throw new NotFoundException("PurchaseEvaluation", request.Id);
|
||||
|
||||
if (entity.Phase != PurchaseEvaluationPhase.DangSoanThao)
|
||||
throw new ConflictException("Chỉ sửa được phiếu khi ở phase Đang soạn thảo.");
|
||||
if (entity.Phase != PurchaseEvaluationPhase.DangSoanThao
|
||||
&& entity.Phase != PurchaseEvaluationPhase.TraLai)
|
||||
throw new ConflictException("Chỉ sửa được phiếu khi ở phase Nháp hoặc Trả lại.");
|
||||
|
||||
// Validate ApprovalWorkflowId V2 nếu thay đổi (Mig 23).
|
||||
if (request.ApprovalWorkflowId is Guid awId && awId != entity.ApprovalWorkflowId)
|
||||
{
|
||||
var aw = await db.ApprovalWorkflows.AsNoTracking()
|
||||
.FirstOrDefaultAsync(w => w.Id == awId, ct)
|
||||
?? throw new NotFoundException("ApprovalWorkflow", awId);
|
||||
var expectedType = entity.Type switch
|
||||
{
|
||||
PurchaseEvaluationType.DuyetNcc => Domain.ApprovalWorkflowsV2.ApprovalWorkflowApplicableType.DuyetNcc,
|
||||
PurchaseEvaluationType.DuyetNccPhuongAn => Domain.ApprovalWorkflowsV2.ApprovalWorkflowApplicableType.DuyetNccPhuongAn,
|
||||
_ => throw new ConflictException($"PurchaseEvaluationType {entity.Type} chưa map sang ApprovalWorkflowApplicableType."),
|
||||
};
|
||||
if (aw.ApplicableType != expectedType)
|
||||
throw new ConflictException($"Quy trình {aw.Code} áp dụng cho {aw.ApplicableType}, không khớp với loại phiếu {entity.Type}.");
|
||||
}
|
||||
|
||||
// Validate Budget link nếu thay đổi.
|
||||
if (request.BudgetId is Guid bid && bid != entity.BudgetId)
|
||||
@ -153,6 +190,7 @@ public class UpdatePurchaseEvaluationDraftCommandHandler(
|
||||
entity.BudgetId = request.BudgetId;
|
||||
entity.BudgetManualName = request.BudgetManualName;
|
||||
entity.BudgetManualAmount = request.BudgetManualAmount;
|
||||
entity.ApprovalWorkflowId = request.ApprovalWorkflowId; // Mig 23 — User đổi quy trình
|
||||
|
||||
db.PurchaseEvaluationChangelogs.Add(new PurchaseEvaluationChangelog
|
||||
{
|
||||
@ -409,6 +447,24 @@ public class GetPurchaseEvaluationQueryHandler(
|
||||
policy = PurchaseEvaluationPolicyRegistry.ForEvaluation(e);
|
||||
}
|
||||
|
||||
// Mig 23 — load ApprovalWorkflow V2 info nếu pin (Code/Name/Version
|
||||
// hiển thị FE detail card "QT-DN-V2-001 - Tên (v01)").
|
||||
string? awCode = null, awName = null;
|
||||
int? awVersion = null;
|
||||
if (e.ApprovalWorkflowId is Guid awId)
|
||||
{
|
||||
var aw = await db.ApprovalWorkflows.AsNoTracking()
|
||||
.Where(w => w.Id == awId)
|
||||
.Select(w => new { w.Code, w.Name, w.Version })
|
||||
.FirstOrDefaultAsync(ct);
|
||||
if (aw is not null)
|
||||
{
|
||||
awCode = aw.Code;
|
||||
awName = aw.Name;
|
||||
awVersion = aw.Version;
|
||||
}
|
||||
}
|
||||
|
||||
return new PurchaseEvaluationDetailBundleDto(
|
||||
e.Id, e.MaPhieu, e.Type, e.Phase, e.TenGoiThau, e.DiaDiem, e.MoTa,
|
||||
e.ProjectId, project?.Name ?? "",
|
||||
@ -419,6 +475,7 @@ public class GetPurchaseEvaluationQueryHandler(
|
||||
e.PaymentTerms, e.SlaDeadline, e.CreatedAt, e.UpdatedAt,
|
||||
e.BudgetId, budgetSummary,
|
||||
e.BudgetManualName, e.BudgetManualAmount,
|
||||
e.ApprovalWorkflowId, awCode, awName, awVersion,
|
||||
e.Suppliers
|
||||
.OrderBy(s => s.Order)
|
||||
.Select(s => new PurchaseEvaluationSupplierDto(
|
||||
|
||||
@ -18,7 +18,8 @@ public class PurchaseEvaluation : AuditableEntity
|
||||
public string? DiaDiem { get; set; } // Lô K, KCN Lộc An...
|
||||
public string? MoTa { get; set; }
|
||||
|
||||
public Guid? WorkflowDefinitionId { get; set; } // Pinned at create — config y như HĐ
|
||||
public Guid? WorkflowDefinitionId { get; set; } // [LEGACY Mig 21] Pinned at create — config y như HĐ
|
||||
public Guid? ApprovalWorkflowId { get; set; } // [Mig 23 Session 17] Pin schema mới ApprovalWorkflowsV2
|
||||
public DateTime? SlaDeadline { get; set; }
|
||||
public bool SlaWarningSent { get; set; }
|
||||
|
||||
|
||||
@ -27,9 +27,18 @@ public class PurchaseEvaluationConfiguration : IEntityTypeConfiguration<Purchase
|
||||
b.HasIndex(x => x.ProjectId);
|
||||
b.HasIndex(x => x.SlaDeadline);
|
||||
b.HasIndex(x => x.WorkflowDefinitionId);
|
||||
b.HasIndex(x => x.ApprovalWorkflowId);
|
||||
b.HasIndex(x => x.ContractId);
|
||||
b.HasIndex(x => x.BudgetId);
|
||||
|
||||
// FK ApprovalWorkflowId Restrict (Mig 23 Session 17) — schema mới
|
||||
// ApprovalWorkflowsV2 pin lúc create. Restrict để KHÔNG xóa workflow
|
||||
// nếu còn phiếu pin.
|
||||
b.HasOne<SolutionErp.Domain.ApprovalWorkflowsV2.ApprovalWorkflow>()
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.ApprovalWorkflowId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.HasMany(x => x.Suppliers).WithOne(s => s.PurchaseEvaluation).HasForeignKey(s => s.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasMany(x => x.Details).WithOne(d => d.PurchaseEvaluation).HasForeignKey(d => d.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasMany(x => x.Approvals).WithOne(a => a.PurchaseEvaluation).HasForeignKey(a => a.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddApprovalWorkflowIdToPurchaseEvaluation : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "ApprovalWorkflowId",
|
||||
table: "PurchaseEvaluations",
|
||||
type: "uniqueidentifier",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PurchaseEvaluations_ApprovalWorkflowId",
|
||||
table: "PurchaseEvaluations",
|
||||
column: "ApprovalWorkflowId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_PurchaseEvaluations_ApprovalWorkflows_ApprovalWorkflowId",
|
||||
table: "PurchaseEvaluations",
|
||||
column: "ApprovalWorkflowId",
|
||||
principalTable: "ApprovalWorkflows",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_PurchaseEvaluations_ApprovalWorkflows_ApprovalWorkflowId",
|
||||
table: "PurchaseEvaluations");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_PurchaseEvaluations_ApprovalWorkflowId",
|
||||
table: "PurchaseEvaluations");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ApprovalWorkflowId",
|
||||
table: "PurchaseEvaluations");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2485,6 +2485,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("ApprovalWorkflowId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("BudgetId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
@ -2578,6 +2581,8 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApprovalWorkflowId");
|
||||
|
||||
b.HasIndex("BudgetId");
|
||||
|
||||
b.HasIndex("ContractId");
|
||||
@ -3562,6 +3567,14 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluation", b =>
|
||||
{
|
||||
b.HasOne("SolutionErp.Domain.ApprovalWorkflowsV2.ApprovalWorkflow", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("ApprovalWorkflowId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationApproval", b =>
|
||||
{
|
||||
b.HasOne("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluation", "PurchaseEvaluation")
|
||||
|
||||
Reference in New Issue
Block a user