Добавить CashMemo.cs

Товарник без процентов скидок-надбавок. Только название и сумма
This commit is contained in:
2025-07-22 22:40:42 +00:00
parent 28a669ec4d
commit 1d4c6c7fda

353
CashMemo.cs Normal file
View File

@@ -0,0 +1,353 @@
@using System.Collections.Generic
@using System.Linq
@using Resto.Front.PrintTemplates.Cheques.Razor
@using Resto.Front.PrintTemplates.Cheques.Razor.TemplateModels
@using Resto.Front.PrintTemplates.RmsEntityWrappers
@inherits TemplateBase<ICashMemoCheque>
@{
var order = Model.Order;
var chequeInfo = Model.ChequeInfo;
var session = chequeInfo.Session;
var notDeletedItems = order.Guests.SelectMany(guest => guest.Items).Where(item => item.DeletionInfo == null).ToList();
var fullSum = order.GetFullSum();
var subTotal = fullSum - order.DiscountItems.Where(discountItem => discountItem.IsCategorized && discountItem.PrintDetailedInPrecheque).Sum(discountItem => discountItem.GetDiscountSum());
var vatSum = order.GetVatSumExcludedFromPrice();
var resultSum = subTotal - order.DiscountItems.Where(discountItem => !discountItem.IsCategorized || !discountItem.PrintDetailedInPrecheque).Sum(discountItem => discountItem.GetDiscountSum()) + vatSum;
var changeSum = order.Payments.Sum(p => p.Sum) + order.GetPrepaySum() - resultSum;
var discountItems = order.DiscountItems.ToList();
List<IPaymentItem> prepays;
List<IPaymentItem> paymentsData;
if (order.CloseInfo != null)
{
var paymentDiscounts = order.CloseInfo.DiscountsForPaymentsAsDiscount.ToList();
discountItems.AddRange(paymentDiscounts);
resultSum -= paymentDiscounts.Sum(pd => pd.DiscountSums.Values.Sum());
changeSum = 0;
prepays = order.PrePayments.Where(p => !p.IsProcessedAsDiscount).ToList();
paymentsData = order.Payments.Where(p => !p.Type.ProcessAsDiscount).ToList();
}
else
{
prepays = order.PrePayments.ToList();
paymentsData = order.Payments.ToList();
}
var payments = paymentsData
.Where(p => p.Type.Group != PaymentGroup.Cash)
.Select(p => new { p.Type.Name, p.Sum })
// Показываем сумму наличными так, будто оплачено без сдачи.
// Если наличных платежей нет, все равно явно показываем, что сумма наличными == 0.
.StartWith(new { Name = Resources.Cash, Sum = paymentsData.Where(p => p.Type.Group == PaymentGroup.Cash).Sum(p => p.Sum) - changeSum })
.ToList();
var categorizedDiscountItems = new List<IDiscountItem>();
var nonCategorizedDiscountItems = new List<IDiscountItem>();
foreach (var discountItem in discountItems)
{
if (discountItem.IsCategorized && discountItem.PrintDetailedInPrecheque)
{
categorizedDiscountItems.Add(discountItem);
}
else
{
nonCategorizedDiscountItems.Add(discountItem);
}
}
}
<doc>
@* header *@
<left><split><whitespace-preserve>@Model.CommonInfo.CafeSetup.BillHeader</whitespace-preserve></split></left>
<center>@Resources.CashMemoChequeTitle</center>
<pair fit="left" left="@string.Format(Resources.CashRegisterFormat, session.CashRegisterNumber)" right="@Model.CommonInfo.Group.Name" />
<pair left="@Resources.HeadCashRegisterShift" right="@session.Number" />
<pair left="@Resources.CafeSessionOpenDate" right="@FormatLongDateTime(session.OpenTime)" />
<pair left="@Resources.CurrentDate" right="@FormatLongDateTime(chequeInfo.OperationTime)" />
<pair left="@string.Format(Resources.BillHeaderCashierPattern, chequeInfo.Cashier.GetNameOrEmpty())" right="@string.Format(Resources.BillHeaderOrderNumberPattern, order.Number)" />
@* body *@
<line />
@Products(notDeletedItems, categorizedDiscountItems, order.Table.Section.PrintProductItemCommentInCheque)
<line />
@if (nonCategorizedDiscountItems.Count > 0)
{
<pair left="@Resources.BillFooterTotalPlain" right="@FormatMoney(subTotal)" />
@NonCategorizedDiscounts(nonCategorizedDiscountItems, fullSum)
}
@if (vatSum != 0m)
{
var vatSumsByVat = order.GetIncludedEntries()
.Where(orderEntry => !orderEntry.VatIncludedInPrice)
.GroupBy(orderEntry => orderEntry.Vat)
.Where(group => group.Key != 0m)
.Select(group => new { Vat = group.Key, Sum = group.Sum(orderEntry => orderEntry.ExcludedVat) })
.ToList();
foreach (var vatWithSum in vatSumsByVat)
{
<pair left="@string.Format(Resources.VatFormat, vatWithSum.Vat)" right="@FormatMoney(vatWithSum.Sum)" />
}
if (vatSumsByVat.Count > 1)
{
<pair left="@Resources.VatSum" right="@FormatMoney(vatSum)" />
}
}
@* payments *@
<pair left="@Resources.BillFooterTotalLower" right="@FormatMoney(resultSum)" />
<line />
@foreach (var prepay in prepays)
{
<pair left="@string.Format(Resources.PrepayTemplate, prepay.Type.Name)" right="@FormatMoney(prepay.Sum)" />
}
@foreach (var payment in payments)
{
<pair left="@payment.Name" right="@FormatMoney(payment.Sum)" />
}
<line />
<pair left="@Resources.FooterTotalUpper" right="@FormatMoney(resultSum)" />
@if (Model.Order.Donations.Any())
{
<line />
foreach (var donation in Model.Order.Donations)
{
<pair left="@string.Format(Resources.DonationsPattern, donation.Type.Name, donation.DonationType.Name)"
right="@FormatMoney(donation.Sum)" />
}
}
<line />
@* footer *@
<pair left="@Resources.ItemsCount" right="@itemsCount" />
<left>@string.Format(Resources.SumFormat, FormatMoneyInWords(resultSum))</left>
<np />
<left>@Resources.Released</left>
<fill symbols="_"><np /></fill>
<center>@Resources.MemoChequeSignature</center>
<np />
<center>@string.Format(Resources.AllSumsInFormat, Model.CommonInfo.CafeSetup.CurrencyName)</center>
<np />
<center><split><whitespace-preserve>@Model.CommonInfo.CafeSetup.BillFooter</whitespace-preserve></split></center>
</doc>
@helper Products(List<IOrderItem> orderItems, List<IDiscountItem> categorizedDiscountItems, bool showComments)
{
if (orderItems.Count == 0)
{
@Resources.ZeroChequeBody
}
else
{
<table>
<columns>
<column formatter="split" />
<column align="right" autowidth="" />
<column align="right" autowidth="" />
<column align="right" autowidth="" />
</columns>
<cells>
<ct>@Resources.NameColumnHeader</ct>
<ct>@Resources.AmountShort</ct>
<ct>@Resources.ProductPrice</ct>
<ct>@Resources.ResultSum</ct>
<linecell />
@foreach (var orderItem in orderItems)
{
@Product(orderItem, categorizedDiscountItems, showComments)
}
</cells>
</table>
}
}
@helper Product(IOrderItem orderItem, List<IDiscountItem> categorizedDiscountItems, bool showComments)
{
itemsCount++;
var productItem = orderItem as IProductItem;
if (productItem != null && productItem.CompoundsInfo != null && productItem.CompoundsInfo.IsPrimaryComponent)
{
<c colspan="4">@string.Format("{0} {1}", productItem.CompoundsInfo.ModifierSchemaName, productItem.ProductSize == null ? string.Empty : productItem.ProductSize.Name)</c>
// для разделенной пиццы комменты печатаем под схемой
if (showComments && productItem.Comment != null && !productItem.Comment.Deleted)
{
<c colspan="4">
<table cellspacing="0">
<columns>
<column width="2" />
<column />
</columns>
<cells>
<c />
<c><split>@productItem.Comment.Text</split></c>
</cells>
</table>
</c>
}
// у пиццы не может быть удаленных модификаторов, поэтому берем весь список
foreach (var orderEntry in productItem.ModifierEntries.Where(orderEntry => ModifiersFilter(orderEntry, productItem, true)))
{
itemsCount++;
var productName = orderEntry.ProductCustomName ?? orderEntry.Product.Name;
<c colspan="4"><whitespace-preserve>@(" " + productName)</whitespace-preserve></c>
<c colspan="2"><right>@string.Format("{0} {1} x", FormatAmount(orderEntry.Amount), orderEntry.Product.MeasuringUnit.Name)</right></c>
<ct>@FormatMoney(orderEntry.Price)</ct>
<ct>@FormatMoney(orderEntry.Cost)</ct>
@CategorizedDiscounts(orderEntry, categorizedDiscountItems)
}
}
if (productItem != null && productItem.CompoundsInfo != null)
{
<c colspan="4"><whitespace-preserve>@(" 1/2 " + GetOrderEntryNameWithProductSize(productItem))</whitespace-preserve></c>
}
else
{
<c colspan="4">@GetOrderEntryNameWithProductSize(orderItem)</c>
}
<c colspan="2"><right>@string.Format("{0} {1} x", FormatAmount(orderItem.Amount), orderItem.Product.MeasuringUnit.Name)</right></c>
<ct>@FormatMoney(orderItem.Price)</ct>
<ct>@FormatMoney(orderItem.Cost)</ct>
// здесь комменты для обычных блюд и целых пицц
if (showComments && productItem != null && productItem.Comment != null && !productItem.Comment.Deleted && productItem.CompoundsInfo == null)
{
<c colspan="4">
<table cellspacing="0">
<columns>
<column width="2" />
<column />
</columns>
<cells>
<c />
<c><split>@productItem.Comment.Text</split></c>
</cells>
</table>
</c>
}
@CategorizedDiscounts(orderItem, categorizedDiscountItems)
foreach (var child in GetFilteredChildren(orderItem))
{
itemsCount++;
var productName = child.ProductCustomName ?? child.Product.Name;
<c colspan="4"><whitespace-preserve>@string.Format(" {0}", productName)</whitespace-preserve></c>
<c colspan="2"><right>@string.Format("{0} {1} x", FormatAmount(child.Amount), child.Product.MeasuringUnit.Name)</right></c>
<ct>@FormatMoney(child.Price)</ct>
<ct>@FormatMoney(child.Cost)</ct>
@CategorizedDiscounts(child, categorizedDiscountItems)
}
}
@helper CategorizedDiscounts(IOrderEntry orderEntry, IEnumerable<IDiscountItem> categorizedDiscountItems)
{
foreach (var discountItem in categorizedDiscountItems.Where(d => d.DiscountSums.ContainsKey(orderEntry)))
{
<c colspan="3"><whitespace-preserve>@string.Format(" {0}", discountItem.Type.PrintableName)</whitespace-preserve></c>
<ct>@FormatMoney(-discountItem.GetDiscountSumFor(orderEntry))</ct>
if (discountItem.CardInfo != null && !string.IsNullOrWhiteSpace(discountItem.CardInfo.MaskedCard))
{
<c colspan="4">@string.Format(Resources.CardPattern, discountItem.CardInfo.MaskedCard)</c>
}
}
}
@helper NonCategorizedDiscounts(IEnumerable<IDiscountItem> discountItems, decimal fullSum)
{
<table>
<columns>
<column formatter="split" />
<column align="right" autowidth="" />
<column align="right" autowidth="" />
</columns>
<cells>
@foreach (var discountItem in discountItems)
{
<c colspan="2">@discountItem.Type.PrintableName</c>
<ct>@FormatMoney(-discountItem.GetDiscountSum())</ct>
if (discountItem.CardInfo != null && !string.IsNullOrWhiteSpace(discountItem.CardInfo.MaskedCard))
{
<c colspan="3">@string.Format(Resources.CardPattern, discountItem.CardInfo.MaskedCard)</c>
}
}
</cells>
</table>
}
@functions
{
private int itemsCount;
private static IEnumerable<IOrderEntry> GetFilteredChildren(IOrderItem orderItem)
{
var productItem = orderItem as IProductItem;
if (productItem != null)
return productItem.ModifierEntries.Where(m => ModifiersFilter(m, productItem));
return ((ITimePayServiceItem)orderItem).RateScheduleEntries;
}
private static bool CommonModifiersFilter(bool isCommonModifier, IProductItem parent, bool onlyCommonModifiers)
{
if (parent.CompoundsInfo != null && parent.CompoundsInfo.IsPrimaryComponent)
{
if (onlyCommonModifiers && !isCommonModifier)
return false;
if (!onlyCommonModifiers && isCommonModifier)
return false;
return true;
}
return true;
}
private static bool ModifiersFilter(IModifierEntry modifierEntry, IProductItem parent, bool onlyCommonModifiers = false)
{
if (!CommonModifiersFilter((modifierEntry).IsCommonModifier, parent, onlyCommonModifiers))
return false;
if (modifierEntry.DeletionInfo != null)
return false;
if (modifierEntry.Cost > 0m)
return true;
if (modifierEntry.ChildModifier == null)
return true;
if (!modifierEntry.ChildModifier.HideIfDefaultAmount)
return true;
var amountPerItem = modifierEntry.ChildModifier.AmountIndependentOfParentAmount
? modifierEntry.Amount
: modifierEntry.Amount / GetParentAmount(parent, onlyCommonModifiers);
return amountPerItem != modifierEntry.ChildModifier.DefaultAmount;
}
private static string GetOrderEntryNameWithProductSize(IOrderEntry orderEntry)
{
var productName = orderEntry.ProductCustomName ?? orderEntry.Product.Name;
var productItem = orderEntry as IProductItem;
return productItem == null || productItem.ProductSize == null || productItem.CompoundsInfo != null
? productName
: string.Format(Resources.ProductNameWithSizeFormat, productName, productItem.ProductSize.Name);
}
private static decimal GetParentAmount(IOrderItem parent, bool onlyCommonModifiers)
{
return onlyCommonModifiers ? parent.Amount * 2 : parent.Amount;
}
}