price adjustment and stock adjustments
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ERPCore.Domain.Enums;
|
||||
using ERPCore.Dtos.Common;
|
||||
|
||||
namespace ERPCore.Dtos.Accounts;
|
||||
|
||||
// --- Cash in hand (docs/BANK_DEPOSIT_MODULE_PLAN.md §2, §7.1) ---
|
||||
|
||||
/// <summary>
|
||||
/// One business day's till cash. CashIn is slip/bundle cash plus cash invoice payments received
|
||||
/// that day; CashOut is expense payments made in cash; Deposited is Posted bank deposits for that
|
||||
/// business day. Closing = Opening + NetCash − Deposited, and becomes the next day's Opening.
|
||||
/// Days before the tracking start date carry nothing in: their Opening is 0.
|
||||
/// </summary>
|
||||
public sealed record CashPositionDto(
|
||||
DateOnly Date, decimal Opening, decimal CashIn, decimal CashOut, decimal NetCash, decimal Deposited, decimal Closing);
|
||||
|
||||
/// <summary>
|
||||
/// A day's cash position for the deposit form. <paramref name="AvailableToDeposit"/> is the lowest
|
||||
/// closing balance from that day up to today: a back-dated deposit lowers every later day too.
|
||||
/// <paramref name="DefaultCashAccountCode"/> is the GL cash account the form preselects.
|
||||
/// </summary>
|
||||
public sealed record CashInHandDto(
|
||||
CashPositionDto Position, decimal AvailableToDeposit, int? BranchId, DateOnly? TrackingStartDate, string TimeZone,
|
||||
string? DefaultCashAccountCode);
|
||||
|
||||
public sealed record CashInHandDailyDto(
|
||||
DateOnly From, DateOnly To, IReadOnlyList<CashPositionDto> Days, int? BranchId, DateOnly? TrackingStartDate, string TimeZone);
|
||||
|
||||
// --- Deposits ---
|
||||
|
||||
public sealed record BankDepositDto(
|
||||
int BankDepositId, string DocNo, int BranchId, string? BranchName,
|
||||
DateOnly BusinessDate, DateOnly DepositDate, decimal Amount,
|
||||
long FromGlCashAccountId, string FromCashAccountCode, string FromCashAccountName,
|
||||
long ToGlBankAccountId, string ToBankAccountCode, string ToBankAccountName, string? ToBankName, string? ToAccountNumber,
|
||||
string? DepositSlipNo, string? DepositedBy, string? Remarks,
|
||||
BankDepositStatus Status, string? GlJournalNo, DateTime? GlPostedAt,
|
||||
string? GlReversalJournalNo, string? CancelReason, DateTime? CancelledAt,
|
||||
int CreatedBy, DateTime CreatedAt);
|
||||
|
||||
/// <summary>A page of deposits plus the total amount of every row matching the filter (not just this page).</summary>
|
||||
public sealed record BankDepositListDto(IReadOnlyList<BankDepositDto> Items, PaginationDto Pagination, decimal TotalAmount);
|
||||
|
||||
public sealed record BankDepositListFilter(
|
||||
DateOnly? From, DateOnly? To, int? BranchId, long? BankAccountId, BankDepositStatus? Status);
|
||||
|
||||
public sealed class CreateBankDepositRequest
|
||||
{
|
||||
/// <summary>Required when branching is enabled; otherwise the default branch is used. A branch user always deposits for their own branch.</summary>
|
||||
public int BranchId { get; set; }
|
||||
[Required] public DateOnly BusinessDate { get; set; }
|
||||
/// <summary>When the bank received it; also the GL entry date. Omitted ⇒ the business date.</summary>
|
||||
public DateOnly? DepositDate { get; set; }
|
||||
[Range(0.01, 999_999_999_999)] public decimal Amount { get; set; }
|
||||
[Required] public long FromGlCashAccountId { get; set; }
|
||||
[Required] public long ToGlBankAccountId { get; set; }
|
||||
[StringLength(50)] public string? DepositSlipNo { get; set; }
|
||||
[StringLength(150)] public string? DepositedBy { get; set; }
|
||||
[StringLength(500)] public string? Remarks { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CancelBankDepositRequest
|
||||
{
|
||||
[Required, StringLength(250, MinimumLength = 1)] public string Reason { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ERPCore.Domain.Enums;
|
||||
|
||||
namespace ERPCore.Dtos.Approvals;
|
||||
|
||||
/// <summary>One decision in a document's approval trail.</summary>
|
||||
public sealed record ApprovalStepDto(int Level, ApprovalDecision Decision, int DecidedBy, string? DecidedByName, DateTime DecidedAt, string? Comment);
|
||||
|
||||
/// <summary>Settings → Approvals (docs/DUAL_APPROVAL_PLAN.md §7).</summary>
|
||||
public sealed record ApprovalConfigDto(
|
||||
int StockAdjustmentLevels, decimal StockAdjustmentLevel2ThresholdValue,
|
||||
int PriceAdjustmentLevels, decimal PriceAdjustmentLevel2ThresholdPercent,
|
||||
IReadOnlyList<string> Level2RoleCodes, DateTime? UpdatedAt);
|
||||
|
||||
public sealed class UpdateApprovalConfigRequest
|
||||
{
|
||||
[Range(0, 2)] public int StockAdjustmentLevels { get; set; }
|
||||
[Range(0, double.MaxValue)] public decimal StockAdjustmentLevel2ThresholdValue { get; set; }
|
||||
[Range(0, 2)] public int PriceAdjustmentLevels { get; set; }
|
||||
[Range(0, 1000)] public decimal PriceAdjustmentLevel2ThresholdPercent { get; set; }
|
||||
public List<string> Level2RoleCodes { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class ApproveRequest
|
||||
{
|
||||
[StringLength(250)] public string? Comment { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RejectRequest
|
||||
{
|
||||
[Required, StringLength(250, MinimumLength = 1)] public string Reason { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A request waiting in the Approvals inbox. <paramref name="Level"/> is the approval it waits for
|
||||
/// (1 or 2) of <paramref name="RequiredApprovals"/>; <paramref name="CanApprove"/> says whether the
|
||||
/// current user may decide it (not the requester, not the level-1 approver, has the right role).
|
||||
/// </summary>
|
||||
public sealed record PendingApprovalDto(
|
||||
string DocType, int DocId, string DocNo, string Summary, int Level, int RequiredApprovals,
|
||||
int RequestedBy, string? RequestedByName, DateTime RequestedAt, bool CanApprove, string? WhyNot);
|
||||
|
||||
public sealed record PendingApprovalsDto(IReadOnlyList<PendingApprovalDto> Items, int ActionableCount);
|
||||
@@ -4,6 +4,9 @@ using ERPCore.Domain.Enums;
|
||||
namespace ERPCore.Dtos.Customers;
|
||||
|
||||
/// <summary>Customer resource used by sales documents.</summary>
|
||||
/// <param name="OutstandingAmount">Unpaid balance across the customer's Posted sales invoices. Filled on the list only.</param>
|
||||
/// <param name="OutstandingInvoiceCount">Posted sales invoices with a balance still due. Filled on the list only.</param>
|
||||
/// <param name="LastPaymentDate">When the customer last paid against an invoice; null if never. Filled on the list only.</param>
|
||||
public sealed record CustomerDto(
|
||||
int CustomerId,
|
||||
string CustomerCode,
|
||||
@@ -23,7 +26,10 @@ public sealed record CustomerDto(
|
||||
EntityStatus Status,
|
||||
int BranchId,
|
||||
DateTime CreatedAt,
|
||||
DateTime? UpdatedAt);
|
||||
DateTime? UpdatedAt,
|
||||
decimal OutstandingAmount = 0m,
|
||||
int OutstandingInvoiceCount = 0,
|
||||
DateTime? LastPaymentDate = null);
|
||||
|
||||
public sealed class CreateCustomerRequest
|
||||
{
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ERPCore.Domain.Enums;
|
||||
|
||||
namespace ERPCore.Dtos.Expenses;
|
||||
|
||||
// --- Setup: categories and titles (docs/EXPENSE_MODULE_PLAN.md §6 "Setup") ---
|
||||
|
||||
public sealed record ExpenseTitleDto(
|
||||
int ExpenseTitleId, int ExpenseCategoryId, string Name, string GlExpenseAccountCode,
|
||||
bool IsSystem, EntityStatus Status, int SortOrder);
|
||||
|
||||
public sealed record ExpenseCategoryDto(
|
||||
int ExpenseCategoryId, string Code, string Name, bool IsSystem, EntityStatus Status, int SortOrder,
|
||||
IReadOnlyList<ExpenseTitleDto> Titles);
|
||||
|
||||
public sealed class UpdateExpenseCategoryRequest
|
||||
{
|
||||
/// <summary>Ignored-if-unchanged for system rows; a different name on a system row is rejected.</summary>
|
||||
[Required, StringLength(100, MinimumLength = 1)] public string Name { get; set; } = string.Empty;
|
||||
public EntityStatus Status { get; set; } = EntityStatus.Active;
|
||||
}
|
||||
|
||||
public sealed class CreateExpenseTitleRequest
|
||||
{
|
||||
[Required, StringLength(100, MinimumLength = 1)] public string Name { get; set; } = string.Empty;
|
||||
[Required, StringLength(20, MinimumLength = 1)] public string GlExpenseAccountCode { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class UpdateExpenseTitleRequest
|
||||
{
|
||||
/// <summary>Ignored-if-unchanged for system rows; a different name on a system row is rejected.</summary>
|
||||
[Required, StringLength(100, MinimumLength = 1)] public string Name { get; set; } = string.Empty;
|
||||
[Required, StringLength(20, MinimumLength = 1)] public string GlExpenseAccountCode { get; set; } = string.Empty;
|
||||
public EntityStatus Status { get; set; } = EntityStatus.Active;
|
||||
}
|
||||
|
||||
// --- Expenses ---
|
||||
|
||||
public sealed record ExpenseSummaryDto(
|
||||
int ExpenseId, string DocNo, int BranchId, DateOnly ExpenseDate, DateOnly? DueDate,
|
||||
int ExpenseCategoryId, string CategoryName, int ExpenseTitleId, string TitleName,
|
||||
string? Payee, string? BillReference, string? PeriodMonth,
|
||||
decimal Amount, decimal PaidAmount, decimal BalanceAmount,
|
||||
ExpenseStatus Status, ExpensePaymentStatus PaymentStatus, string? GlJournalNo, DateTime CreatedAt);
|
||||
|
||||
public sealed record ExpensePaymentDto(
|
||||
int ExpensePaymentId, int ExpenseId, decimal Amount, DateTime PaymentDate, ExpensePaymentMethod PaymentMethod,
|
||||
long GlBankAccountId, string BankAccountName, string? ChequeNo, string? Reference, string? GlJournalNo, DateTime CreatedAt);
|
||||
|
||||
public sealed record ExpenseDto(
|
||||
int ExpenseId, string DocNo, int BranchId, DateOnly ExpenseDate, DateOnly? DueDate,
|
||||
int ExpenseCategoryId, string CategoryName, int ExpenseTitleId, string TitleName,
|
||||
string? Payee, int? VendorId, string? VendorName, string? BillReference, string? Description, string? PeriodMonth,
|
||||
decimal Amount, decimal PaidAmount, decimal BalanceAmount,
|
||||
ExpenseStatus Status, ExpensePaymentStatus PaymentStatus,
|
||||
string? GlExpenseAccountCode, string? GlJournalNo, DateTime? GlPostedAt, string? GlReversalJournalNo, string? CancelReason,
|
||||
int CreatedBy, DateTime CreatedAt, DateTime? UpdatedAt,
|
||||
IReadOnlyList<ExpensePaymentDto> Payments);
|
||||
|
||||
public class ExpenseRequestBase
|
||||
{
|
||||
/// <summary>Required when branching is enabled; otherwise the default branch is used.</summary>
|
||||
public int BranchId { get; set; }
|
||||
[Required] public DateOnly ExpenseDate { get; set; }
|
||||
public DateOnly? DueDate { get; set; }
|
||||
[Required] public int ExpenseCategoryId { get; set; }
|
||||
[Required] public int ExpenseTitleId { get; set; }
|
||||
[StringLength(150)] public string? Payee { get; set; }
|
||||
public int? VendorId { get; set; }
|
||||
[StringLength(50)] public string? BillReference { get; set; }
|
||||
[StringLength(500)] public string? Description { get; set; }
|
||||
[RegularExpression(@"^\d{4}-(0[1-9]|1[0-2])$", ErrorMessage = "PeriodMonth must be yyyy-MM.")]
|
||||
public string? PeriodMonth { get; set; }
|
||||
[Range(0.01, 999_999_999_999)] public decimal Amount { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateExpenseRequest : ExpenseRequestBase;
|
||||
|
||||
public sealed class UpdateExpenseRequest : ExpenseRequestBase;
|
||||
|
||||
public sealed class CancelExpenseRequest
|
||||
{
|
||||
[Required, StringLength(250, MinimumLength = 1)] public string Reason { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class ExpensePaymentLineRequest
|
||||
{
|
||||
[Required] public long GlBankAccountId { get; set; }
|
||||
[Range(0.01, double.MaxValue)] public decimal Amount { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One payment submission: one or more lines (e.g. part cash, part bank), all posted in a
|
||||
/// single GL journal entry. Total must not exceed the balance (for Post & Pay, the amount); partial is fine.
|
||||
/// </summary>
|
||||
public sealed class CreateExpensePaymentRequest
|
||||
{
|
||||
[Required, MinLength(1)] public List<ExpensePaymentLineRequest> Lines { get; set; } = new();
|
||||
public ExpensePaymentMethod PaymentMethod { get; set; } = ExpensePaymentMethod.Cash;
|
||||
/// <summary>Required when <see cref="PaymentMethod"/> is Cheque.</summary>
|
||||
[StringLength(30)] public string? ChequeNo { get; set; }
|
||||
[StringLength(100)] public string? Reference { get; set; }
|
||||
/// <summary>When it was paid; also the GL entry date. Omitted ⇒ today. Never in the future.</summary>
|
||||
public DateOnly? PaymentDate { get; set; }
|
||||
}
|
||||
|
||||
public sealed record ExpenseListFilter(
|
||||
ExpenseStatus? Status, ExpensePaymentStatus? PaymentStatus, int? CategoryId, int? TitleId,
|
||||
DateOnly? From, DateOnly? To, bool OverdueOnly);
|
||||
|
||||
public sealed record ExpenseTitleTotalDto(int ExpenseTitleId, string TitleName, decimal Amount, int Count);
|
||||
|
||||
public sealed record ExpenseCategoryTotalDto(
|
||||
int ExpenseCategoryId, string CategoryName, decimal Amount, int Count, IReadOnlyList<ExpenseTitleTotalDto> Titles);
|
||||
|
||||
/// <summary>Posted (non-cancelled) expenses dated within [From, To], plus the all-time unpaid/overdue position.</summary>
|
||||
public sealed record ExpenseSummaryReportDto(
|
||||
DateOnly From, DateOnly To, decimal TotalAmount, decimal PaidAmount, decimal UnpaidAmount, int Count,
|
||||
decimal OutstandingAmount, decimal OverdueAmount, int OverdueCount, int DraftCount,
|
||||
IReadOnlyList<ExpenseCategoryTotalDto> Categories);
|
||||
@@ -2,6 +2,14 @@ using ERPCore.Domain.Enums;
|
||||
|
||||
namespace ERPCore.Dtos.Items;
|
||||
|
||||
/// <summary>
|
||||
/// One posted GRN receipt of an item — what it was bought at. <paramref name="NetUnitCost"/> is the
|
||||
/// cost after trade discount (the FIFO stock cost, VAT excluded) — the figure to price against.
|
||||
/// </summary>
|
||||
public sealed record ItemPurchasePriceDto(
|
||||
int GrnId, string GrnDocNo, DateTime ReceivedAt, int VendorId, string? VendorName, string? WarehouseCode,
|
||||
decimal Qty, decimal UnitCost, decimal DiscountPct, decimal NetUnitCost, decimal VatPct);
|
||||
|
||||
/// <summary>
|
||||
/// Item row enriched with cross-module aggregates (current FIFO stock value, low-stock
|
||||
/// flag, last purchase, trailing-30-day sales) for the Items list page. Deliberately a
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ERPCore.Domain.Enums;
|
||||
using ERPCore.Dtos.Approvals;
|
||||
|
||||
namespace ERPCore.Dtos.Products;
|
||||
|
||||
/// <summary>One item's requested change. Current* are the item's prices now — they differ from Old* when it was repriced since.</summary>
|
||||
public sealed record PriceAdjustmentLineDto(
|
||||
int PriceAdjustmentLineId, int ItemId, string Sku, string ItemName,
|
||||
decimal? OldMinPrice, decimal? OldMaxPrice, decimal? OldFlatPrice,
|
||||
decimal? NewMinPrice, decimal? NewMaxPrice, decimal? NewFlatPrice,
|
||||
decimal? CurrentMinPrice, decimal? CurrentMaxPrice, decimal? CurrentFlatPrice);
|
||||
|
||||
public sealed record PriceAdjustmentSummaryDto(
|
||||
int PriceAdjustmentId, string DocNo, string Reason, PriceAdjustmentStatus Status, int RequiredApprovals, int? PendingLevel,
|
||||
int LineCount, int CreatedBy, string? CreatedByName, DateTime CreatedAt, DateTime? AppliedAt);
|
||||
|
||||
/// <param name="PendingLevel">The approval it waits for (1 or 2); null once decided.</param>
|
||||
public sealed record PriceAdjustmentDto(
|
||||
int PriceAdjustmentId, string DocNo, string Reason, PriceAdjustmentStatus Status, int RequiredApprovals, int? PendingLevel,
|
||||
int CreatedBy, string? CreatedByName, DateTime CreatedAt,
|
||||
int? ApprovedLevel1By, DateTime? ApprovedLevel1At, int? ApprovedLevel2By, DateTime? ApprovedLevel2At,
|
||||
int? RejectedBy, DateTime? RejectedAt, string? RejectReason, DateTime? CancelledAt, DateTime? AppliedAt,
|
||||
IReadOnlyList<PriceAdjustmentLineDto> Lines, IReadOnlyList<ApprovalStepDto> ApprovalHistory, bool CanApprove, string? WhyNot,
|
||||
bool CanWithdraw);
|
||||
|
||||
public sealed class PriceAdjustmentLineInput
|
||||
{
|
||||
[Required] public int ItemId { get; set; }
|
||||
/// <summary>The prices the item should have afterwards — null clears that price.</summary>
|
||||
[Range(0, double.MaxValue)] public decimal? NewMinPrice { get; set; }
|
||||
[Range(0, double.MaxValue)] public decimal? NewMaxPrice { get; set; }
|
||||
[Range(0, double.MaxValue)] public decimal? NewFlatPrice { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreatePriceAdjustmentRequest
|
||||
{
|
||||
[Required, StringLength(250, MinimumLength = 1)] public string Reason { get; set; } = string.Empty;
|
||||
[Required, MinLength(1)] public List<PriceAdjustmentLineInput> Lines { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed record ItemPriceHistoryDto(
|
||||
int ItemPriceHistoryId, int ItemId, int? PriceAdjustmentId, string? DocNo,
|
||||
decimal? OldMinPrice, decimal? OldMaxPrice, decimal? OldFlatPrice,
|
||||
decimal? NewMinPrice, decimal? NewMaxPrice, decimal? NewFlatPrice,
|
||||
int RequestedBy, string? RequestedByName, int? ApprovedLevel1By, string? ApprovedLevel1ByName,
|
||||
int? ApprovedLevel2By, string? ApprovedLevel2ByName, DateTime AppliedAt);
|
||||
@@ -0,0 +1,51 @@
|
||||
namespace ERPCore.Dtos.Reports;
|
||||
|
||||
/// <summary>
|
||||
/// One business day's figures (or, with <see cref="Date"/> null, a range's totals) — docs/DAY_END_SALES_REPORT_PLAN.md §4.
|
||||
/// Sales are Posted slips, bundle sales and invoices dated that day; Paid is what has been paid on
|
||||
/// those sales so far (split by how it was paid) and Due the rest.
|
||||
/// </summary>
|
||||
/// <param name="Income">TotalSales − ExpenseTotal (sales returns aren't priced, so they can't be netted off).</param>
|
||||
/// <param name="CostOfGoodsSold">FIFO cost of the stock those sales issued (the stock ledger's Out value).</param>
|
||||
/// <param name="GrossProfit">TotalSales − CostOfGoodsSold.</param>
|
||||
/// <param name="NetProfit">GrossProfit − ExpenseTotal; negative is a loss.</param>
|
||||
/// <param name="EarlierInvoiceCollections">Invoice payments received this day against invoices from
|
||||
/// earlier days — not part of PaidAmount.</param>
|
||||
/// <param name="NetCash">Cash that came in this day (slip/bundle cash + cash invoice payments, any
|
||||
/// invoice) minus expenses paid in cash this day — a till check.</param>
|
||||
/// <param name="OpeningCashInHand">Cash left in the till from earlier days (docs/BANK_DEPOSIT_MODULE_PLAN.md §9).
|
||||
/// For a range's totals, the first day's opening.</param>
|
||||
/// <param name="CashDeposited">Posted bank deposits made against this business day.</param>
|
||||
/// <param name="ClosingCashInHand">Opening + NetCash − CashDeposited: cash still in hand. For a range's totals, the last day's closing.</param>
|
||||
public sealed record DayEndReportDayDto(
|
||||
DateOnly? Date,
|
||||
decimal TotalSales, decimal PaidAmount, decimal DueAmount,
|
||||
decimal PaidByCash, decimal PaidByCard, decimal PaidByOther,
|
||||
int SalesCount, int CashSalesCount, int CardSalesCount, int MixedSalesCount, int OtherSalesCount, int UnpaidSalesCount,
|
||||
decimal ExpenseTotal, decimal Income,
|
||||
decimal CostOfGoodsSold, decimal GrossProfit, decimal NetProfit,
|
||||
decimal EarlierInvoiceCollections,
|
||||
decimal NetCash,
|
||||
decimal OpeningCashInHand, decimal CashDeposited, decimal ClosingCashInHand);
|
||||
|
||||
/// <summary>One sale of the day. <paramref name="PaidBy"/> is Cash, Card, Bank transfer, Cheque, Mixed or Unpaid.</summary>
|
||||
public sealed record DayEndReportSaleDto(
|
||||
string DocType, int DocId, string DocNo, DateTime At, string CustomerName,
|
||||
decimal Total, decimal Paid, decimal Due, string PaidBy, decimal Cost, decimal GrossProfit);
|
||||
|
||||
public sealed record DayEndReportExpenseDto(
|
||||
int ExpenseId, string DocNo, string CategoryName, string TitleName, string? Payee, decimal Amount, decimal PaidAmount);
|
||||
|
||||
/// <summary>A Posted bank deposit of this business day's cash.</summary>
|
||||
public sealed record DayEndReportDepositDto(
|
||||
int BankDepositId, string DocNo, string BankAccountName, string? BankName, string? AccountNumber,
|
||||
string? DepositSlipNo, DateOnly DepositDate, decimal Amount);
|
||||
|
||||
/// <summary>A single day: its figures plus the sales, expenses and bank deposits behind them.</summary>
|
||||
public sealed record DayEndReportDto(
|
||||
DayEndReportDayDto Summary, IReadOnlyList<DayEndReportSaleDto> Sales, IReadOnlyList<DayEndReportExpenseDto> Expenses,
|
||||
IReadOnlyList<DayEndReportDepositDto> Deposits, int? BranchId, string TimeZone);
|
||||
|
||||
/// <summary>Day-wise figures for a range (every day present, zeros on quiet days) plus the range's totals.</summary>
|
||||
public sealed record DayEndDailyReportDto(
|
||||
DateOnly From, DateOnly To, IReadOnlyList<DayEndReportDayDto> Days, DayEndReportDayDto Totals, int? BranchId, string TimeZone);
|
||||
@@ -12,7 +12,7 @@ public sealed record BundleSaleDto(
|
||||
int WarehouseId, int CashierUserId, int BundleSaleTemplateId, string BundleName, string BundleCode,
|
||||
BundleSaleStatus Status, decimal ComponentSubtotal, decimal BundlePrice, decimal MarginAmount,
|
||||
decimal DiscountTotal, decimal TaxTotal, decimal GrandTotal, DateTime CreatedAt, DateTime? UpdatedAt,
|
||||
IReadOnlyList<BundleSaleLineDto> Lines);
|
||||
IReadOnlyList<BundleSaleLineDto> Lines, decimal CashAmount, decimal CardAmount);
|
||||
|
||||
public sealed record BundleSaleSummaryDto(
|
||||
int BundleSaleId, string BundleNo, DateTime BundleDate, int CustomerId, string CustomerSnapshotName,
|
||||
@@ -66,6 +66,8 @@ public sealed class CreateBundleSaleRequest
|
||||
[Range(0, double.MaxValue)] public decimal BundlePrice { get; set; }
|
||||
public bool AllowPriceOverride { get; set; }
|
||||
[Required, MinLength(1)] public List<CreateBundleSaleTemplateLineRequest> Lines { get; set; } = new();
|
||||
/// <summary>The part of the total tendered by card; the rest is cash. Omit for all cash.</summary>
|
||||
[Range(0, double.MaxValue)] public decimal? CardAmount { get; set; }
|
||||
}
|
||||
|
||||
public sealed class UpdateBundleSaleRequest
|
||||
@@ -78,4 +80,6 @@ public sealed class UpdateBundleSaleRequest
|
||||
[Range(0, double.MaxValue)] public decimal BundlePrice { get; set; }
|
||||
public bool AllowPriceOverride { get; set; }
|
||||
[Required, MinLength(1)] public List<CreateBundleSaleTemplateLineRequest> Lines { get; set; } = new();
|
||||
/// <summary>See <see cref="CreateBundleSaleRequest.CardAmount"/>.</summary>
|
||||
[Range(0, double.MaxValue)] public decimal? CardAmount { get; set; }
|
||||
}
|
||||
|
||||
@@ -31,12 +31,15 @@ public sealed record SalesInvoiceSummaryDto(
|
||||
|
||||
public sealed record SalesInvoicePaymentDto(
|
||||
int SalesInvoicePaymentId, int SalesInvoiceId, decimal Amount, DateTime PaymentDate,
|
||||
long GlBankAccountId, string BankAccountName, string? Reference, string? GlJournalNo, DateTime CreatedAt);
|
||||
long GlBankAccountId, string BankAccountName, string? Reference, string? GlJournalNo, DateTime CreatedAt,
|
||||
SalesPaymentMethod PaymentMethod);
|
||||
|
||||
public sealed class CreateSalesInvoicePaymentRequest
|
||||
{
|
||||
[Range(0.01, double.MaxValue)] public decimal Amount { get; set; }
|
||||
[Required] public long GlBankAccountId { get; set; }
|
||||
/// <summary>How the customer paid. Omitted ⇒ derived from the account: a Cash account ⇒ Cash, a Bank account ⇒ Card.</summary>
|
||||
public SalesPaymentMethod? PaymentMethod { get; set; }
|
||||
[StringLength(100)] public string? Reference { get; set; }
|
||||
/// <summary>When the customer paid; also the GL entry date. Omitted ⇒ today. Never in the future.</summary>
|
||||
public DateOnly? PaymentDate { get; set; }
|
||||
@@ -47,6 +50,8 @@ public sealed class BulkSalesInvoicePaymentLine
|
||||
{
|
||||
[Range(0.01, double.MaxValue)] public decimal Amount { get; set; }
|
||||
[Required] public long GlBankAccountId { get; set; }
|
||||
/// <summary>See <see cref="CreateSalesInvoicePaymentRequest.PaymentMethod"/>.</summary>
|
||||
public SalesPaymentMethod? PaymentMethod { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,7 @@ public sealed record SalesSlipLineDto(
|
||||
|
||||
public sealed record SalesSlipTotalsDto(
|
||||
decimal Subtotal, decimal DiscountTotal, decimal FreeQtyTotal, decimal TaxTotal, decimal GrandTotal,
|
||||
decimal PaidAmount, decimal BalanceAmount);
|
||||
decimal PaidAmount, decimal BalanceAmount, decimal CashAmount, decimal CardAmount);
|
||||
|
||||
public sealed record SalesSlipDto(
|
||||
int SalesSlipId, string SlipNo, DateTime SlipDate, int CustomerId,
|
||||
@@ -87,6 +87,10 @@ public sealed class CreateSalesSlipRequest
|
||||
/// Receivable when it posts (see SalesDayEndService.CloseAsync).
|
||||
/// </summary>
|
||||
[Range(0, double.MaxValue)] public decimal? PaidAmount { get; set; }
|
||||
|
||||
/// <summary>The part of the paid amount tendered by card; the rest of it is cash. Omit for all
|
||||
/// cash. Must be between 0 and the paid amount.</summary>
|
||||
[Range(0, double.MaxValue)] public decimal? CardAmount { get; set; }
|
||||
}
|
||||
|
||||
public sealed class UpdateSalesSlipRequest
|
||||
@@ -98,4 +102,7 @@ public sealed class UpdateSalesSlipRequest
|
||||
|
||||
/// <summary>See <see cref="CreateSalesSlipRequest.PaidAmount"/>.</summary>
|
||||
[Range(0, double.MaxValue)] public decimal? PaidAmount { get; set; }
|
||||
|
||||
/// <summary>See <see cref="CreateSalesSlipRequest.CardAmount"/>.</summary>
|
||||
[Range(0, double.MaxValue)] public decimal? CardAmount { get; set; }
|
||||
}
|
||||
|
||||
@@ -5,17 +5,29 @@ namespace ERPCore.Dtos.Stock;
|
||||
|
||||
// Responses (docs/11 §5.5) ------------------------------------------------------
|
||||
|
||||
public sealed record AdjustmentLineDto(int AdjLineId, int ItemId, int? BinId, int? BatchId, decimal QtyDelta, int? SerialId);
|
||||
/// <param name="RequestedSerialIds">Serials named to write off (shown while the request is pending).</param>
|
||||
/// <param name="RequestedSerialNos">Serial numbers named as found (shown while the request is pending).</param>
|
||||
public sealed record AdjustmentLineDto(
|
||||
int AdjLineId, int ItemId, int? BinId, int? BatchId, decimal QtyDelta, int? SerialId,
|
||||
IReadOnlyList<int>? RequestedSerialIds = null, IReadOnlyList<string>? RequestedSerialNos = null);
|
||||
|
||||
/// <param name="PendingLevel">The approval it waits for (1 or 2); null once decided or posted.</param>
|
||||
/// <param name="CanApprove">Whether the current user may give that approval; <paramref name="WhyNot"/> says why not.</param>
|
||||
public sealed record AdjustmentDto(
|
||||
int AdjustmentId, string DocNo, int WarehouseId, int BranchId, int ReasonCodeId, AdjustmentStatus Status,
|
||||
int CreatedBy, DateTime CreatedAt, string? GlJournalNo, DateTime? GlPostedAt,
|
||||
IReadOnlyList<AdjustmentLineDto> Lines, IReadOnlyList<int> LedgerRefs);
|
||||
IReadOnlyList<AdjustmentLineDto> Lines, IReadOnlyList<int> LedgerRefs,
|
||||
int RequiredApprovals = 0, int? PendingLevel = null,
|
||||
int? ApprovedLevel1By = null, DateTime? ApprovedLevel1At = null, int? ApprovedLevel2By = null, DateTime? ApprovedLevel2At = null,
|
||||
int? RejectedBy = null, DateTime? RejectedAt = null, string? RejectReason = null, DateTime? PostedAt = null,
|
||||
IReadOnlyList<Approvals.ApprovalStepDto>? ApprovalHistory = null, bool CanApprove = false, string? WhyNot = null,
|
||||
bool CanWithdraw = false, string? CreatedByName = null);
|
||||
|
||||
/// <summary>Row shape for <c>GET /stock-adjustments</c> — no lines/ledgerRefs (those need a per-row query).</summary>
|
||||
public sealed record AdjustmentSummaryDto(
|
||||
int AdjustmentId, string DocNo, int WarehouseId, int BranchId, int ReasonCodeId, AdjustmentStatus Status,
|
||||
int CreatedBy, DateTime CreatedAt, int LineCount, string? GlJournalNo);
|
||||
int CreatedBy, DateTime CreatedAt, int LineCount, string? GlJournalNo,
|
||||
int RequiredApprovals = 0, int? PendingLevel = null);
|
||||
|
||||
// Requests ----------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@ public sealed record CountSummaryDto(
|
||||
int CountId, string DocNo, int WarehouseId, int BranchId, CountType CountType, CountStatus Status,
|
||||
int CreatedBy, DateTime CreatedAt, int LineCount);
|
||||
|
||||
public sealed record CountPostResultDto(int CountId, CountStatus Status, int? AdjustmentId, string? GlJournalNo, IReadOnlyList<int> LedgerRefs);
|
||||
/// <param name="AdjustmentStatus">The variance adjustment's status — <c>PendingApproval</c> when it must be approved before stock moves.</param>
|
||||
public sealed record CountPostResultDto(
|
||||
int CountId, CountStatus Status, int? AdjustmentId, string? GlJournalNo, IReadOnlyList<int> LedgerRefs,
|
||||
AdjustmentStatus? AdjustmentStatus = null, string? AdjustmentDocNo = null);
|
||||
|
||||
// Requests ----------------------------------------------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user