Advertisement
Guest User

Untitled

a guest
Jan 7th, 2019
347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 38.05 KB | None | 0 0
  1. @using System
  2. @using System.Collections.Generic
  3. @using System.Linq
  4. @using System.Diagnostics
  5. @using Resto.Front.PrintTemplates.Reports
  6. @using Resto.Front.PrintTemplates.Reports.TemplateModels
  7. @using Resto.Front.PrintTemplates.RmsEntityWrappers
  8. @using Resto.Front.PrintTemplates.Reports.OlapReports
  9. @using Resto.Front.PrintTemplates.RmsEntityWrappers
  10.  
  11. @* 041 Выручка по типам с налогами *@
  12. @* Парный к 011-му отчет по кассовым данным *@
  13. @inherits TemplateBase
  14. @{
  15.  
  16.     FillData();
  17.     FillSalesData();
  18. }
  19.  
  20. @if (!Model.IsOnlyBodyMarkupRequired)
  21. {
  22.     <doc formatter="split">
  23.         @Header()
  24.         @Body()
  25.         @Footer()
  26.     </doc>
  27. }
  28. else
  29. {
  30.     <doc formatter="split">
  31.         @Body()
  32.     </doc>
  33. }
  34.  
  35. @helper Header()
  36. {
  37.     var terminalName = Model.CashRegister != null
  38.         ? string.Format(Resources.TerminalNumberNamePattern, Model.CashRegister.Number, Model.Group.Name)
  39.         : string.Format(Resources.TerminalNamePattern, Model.CurrentTerminal, Model.Group.Name);
  40.        
  41.     foreach (var headerLine in Model.CafeSetup.ReportHeader.Split(Environment.NewLine.ToCharArray()))
  42.     {
  43.         <left>
  44.             <whitespace-preserve>@headerLine</whitespace-preserve>
  45.         </left>
  46.     }
  47.    
  48.     <np />
  49.     <center>@Model.Name</center>
  50.     <np />
  51.     <pair left="@Resources.HeadTerminal" right="@terminalName" fit="left" />
  52.    
  53.     if (Model.CafeSession != null)
  54.     {
  55.         <pair left="@Resources.HeadCashRegisterShift" right="@Model.CafeSession.Number" fit="right" />
  56.         <pair left="@Resources.HeadCashRegisterShiftOpened" right="@FormatLongDateTime(Model.CafeSession.OpenTime)" fit="right" />
  57.     }
  58.    
  59.     <pair left="@Resources.HeadCurrentTime" right="@FormatLongDateTime(Model.CurrentTime)" fit="right" />
  60.     <table>
  61.         <columns>
  62.             <column autowidth=""/>
  63.             <column align="right"/>
  64.         </columns>
  65.         <cells>
  66.             <ct>@Resources.HeadCurrentUser</ct>
  67.             <ct>@(Model.CurrentUser == null ? string.Empty : Model.CurrentUser.Name)</ct>
  68.         </cells>
  69.     </table>
  70.     <np />
  71.     <center>Подразделение: @Model.Group.Name</center>
  72. }
  73.  
  74. @helper Footer()
  75. {
  76.     <np />
  77.     <center>
  78.         @string.Format(Resources.AllSumsInFormat, Model.CafeSetup.CurrencyName)
  79.     </center>
  80.     <np />
  81. }
  82.  
  83. @helper Body()
  84. {
  85.    var k = 0;
  86.    var Type = "";
  87.     <np />
  88.  
  89.     <center>ПРИХОД</center>
  90.  
  91.     <np />
  92.     <center>Выручка</center>
  93.     <table>
  94.         <columns>
  95.             <column formatter="split" />
  96.             <column align="right" autowidth="" />
  97.         </columns>
  98.         <cells>
  99.           <linecell symbols="-" />
  100.             <ct>@Resources.PaymentType</ct>
  101.             <ct>@Resources.Sum</ct>
  102.  
  103.             <linecell symbols="-" />
  104.      
  105.             @foreach (var groupIsFiscal in salesData)
  106.             {
  107.             var c = 0;
  108.             <c colspan="0"><np /></c>
  109.            
  110.            
  111.                
  112.             foreach (var groupPaymentGroup in groupIsFiscal.Value)
  113.             {
  114.              // Если несколько групп оплаты, то между ними вставляем пустую строку
  115.              if (c++ > 0)
  116.              {
  117.                  <c colspan="0"><np /></c>
  118.              }
  119.                          foreach (var saleInfo in groupPaymentGroup.Value)
  120.                          {
  121.                            Type = saleInfo.PaymentTypeName.ToLower();
  122.                            if (Type.Contains("наличные") || Type.Contains("банковские карты")  || Type.Contains("депозит"))
  123.                            {
  124.                                <c colspan="2">@groupPaymentGroup.Key.GetLocalName()</c>
  125.                                <ct>@string.Format(Resources.TotalSub, groupPaymentGroup.Key.GetLocalName())</ct>
  126.                    <ct>@FormatPrice(saleInfo.Sum)</ct>
  127.                                k= k+ Decimal.ToInt32(saleInfo.Sum);
  128.                          
  129.                          }                                                                                             
  130.                       }
  131.                   }          
  132.               }
  133.                  
  134.             <linecell symbols="-" />  
  135.                 <ct>@Resources.TotalSales</ct>
  136.                 <ct>@FormatPrice(k)</ct>
  137.            
  138.                  
  139.         </cells>
  140.     </table>
  141.    
  142.     <np />
  143.     <np />
  144.     <center>Принятая предоплата</center>
  145.     <np />
  146.     var payments = closedOrdersSource.SelectMany(order => order.Payments).ToList();
  147.     <table>
  148.             <columns>
  149.                 <column autowidth="" />
  150.                 <column formatter="split" />
  151.                 <column formatter="split" />
  152.                 <column align="right" autowidth="" />
  153.             </columns>
  154.             <cells>
  155.                 <c colspan="4"></c>
  156.                 <linecell symbols="-" />
  157.                 <ct>@Resources.OrderColumn</ct>
  158.                 <ct>@Resources.TableColumn</ct>
  159.                 <ct>@Resources.PaymentType</ct>
  160.                 <ct>@Resources.SumTitle</ct>
  161.                 <linecell symbols="-" />
  162.                  
  163.                  @GetPrepay(payments.Where(p => p.PaymentType.Group == PaymentGroup.Cash).ToList(),Resources.PaymentTypeGroupCashTitle)
  164.                  @GetPrepay(payments.Where(p => p.PaymentType.Group == PaymentGroup.Card).ToList(),Resources.PaymentTypeGroupCardTitle)
  165.                  @GetPrepay(payments.Where(p => p.PaymentType.Group == PaymentGroup.NonCash && IsCreditPaymentType(p.PaymentType)).ToList(),Resources.PaymentTypeGroupCreditTitle)
  166.                  @GetPrepay(payments.Where(p => p.PaymentType.Group == PaymentGroup.NonCash && !IsCreditPaymentType(p.PaymentType)).ToList(),Resources.PaymentTypeGroupNonCashTitle)
  167.             </cells>
  168.         </table>
  169.         <table>
  170.             <columns>
  171.                <column formatter="split" />
  172.                <column align="left" autowidth="" />
  173.                <column align="right" autowidth="" />
  174.             </columns>
  175.             <cells>
  176.                <linecell symbols="-" />
  177.                <c>@Resources.PaymentType</c>
  178.                <ct>@Resources.Cheques</ct>
  179.                <ct>@Resources.Sum</ct>
  180.                <linecell symbols="-" />
  181.                @GetTotalPrepay(payments.Where(p => p.PaymentType.Group == PaymentGroup.Cash).ToList(),Resources.PaymentTypeGroupCashTitle)
  182.                @GetTotalPrepay(payments.Where(p => p.PaymentType.Group == PaymentGroup.Card).ToList(),Resources.PaymentTypeGroupCardTitle)
  183.                @GetTotalPrepay(payments.Where(p => p.PaymentType.Group == PaymentGroup.NonCash && IsCreditPaymentType(p.PaymentType)).ToList(),Resources.PaymentTypeGroupCreditTitle)
  184.                @GetTotalPrepay(payments.Where(p => p.PaymentType.Group == PaymentGroup.NonCash && !IsCreditPaymentType(p.PaymentType)).ToList(),Resources.PaymentTypeGroupNonCashTitle)
  185.                <linecell symbols="-" />
  186.                       @GetAllTotalPrepay(payments.ToList())
  187.                <linecell symbols="-" />
  188.            </cells>
  189.         </table>
  190.         <np />
  191.         <center>РАСХОД</center>
  192.         <np />
  193.         <center>Возврат предоплаты</center>
  194.         <np />
  195.         <table>
  196.             <columns>
  197.                 <column autowidth="" />
  198.                 <column formatter="split" />
  199.                 <column formatter="split" />
  200.                 <column align="right" autowidth="" />
  201.             </columns>
  202.             <cells>
  203.                 <c colspan="4"></c>
  204.                 <linecell symbols="-" />
  205.                 <ct>@Resources.OrderColumn</ct>
  206.                 <ct>@Resources.TableColumn</ct>
  207.                 <ct>@Resources.PaymentType</ct>
  208.                 <ct>@Resources.SumTitle</ct>
  209.                 <linecell symbols="-" />
  210.                  
  211.                  @GetPrepayReturn(payments.Where(p => p.PaymentType.Group == PaymentGroup.Cash).ToList(),Resources.PaymentTypeGroupCashTitle)
  212.                  @GetPrepayReturn(payments.Where(p => p.PaymentType.Group == PaymentGroup.Card).ToList(),Resources.PaymentTypeGroupCardTitle)
  213.                  @GetPrepayReturn(payments.Where(p => p.PaymentType.Group == PaymentGroup.NonCash && IsCreditPaymentType(p.PaymentType)).ToList(),Resources.PaymentTypeGroupCreditTitle)
  214.                  @GetPrepayReturn(payments.Where(p => p.PaymentType.Group == PaymentGroup.NonCash && !IsCreditPaymentType(p.PaymentType)).ToList(),Resources.PaymentTypeGroupNonCashTitle)
  215.             </cells>
  216.         </table>
  217.          <table>
  218.             <columns>
  219.                <column formatter="split" />
  220.                <column align="left" autowidth="" />
  221.                <column align="right" autowidth="" />
  222.             </columns>
  223.             <cells>
  224.                <linecell symbols="-" />
  225.                <c>@Resources.PaymentType</c>
  226.                <ct>@Resources.Cheques</ct>
  227.                <ct>@Resources.Sum</ct>
  228.                <linecell symbols="-" />
  229.                @GetTotalPrepayReturn(payments.Where(p => p.PaymentType.Group == PaymentGroup.Cash).ToList(),Resources.PaymentTypeGroupCashTitle)
  230.                @GetTotalPrepayReturn(payments.Where(p => p.PaymentType.Group == PaymentGroup.Card).ToList(),Resources.PaymentTypeGroupCardTitle)
  231.                @GetTotalPrepayReturn(payments.Where(p => p.PaymentType.Group == PaymentGroup.NonCash && IsCreditPaymentType(p.PaymentType)).ToList(),Resources.PaymentTypeGroupCreditTitle)
  232.                @GetTotalPrepayReturn(payments.Where(p => p.PaymentType.Group == PaymentGroup.NonCash && !IsCreditPaymentType(p.PaymentType)).ToList(),Resources.PaymentTypeGroupNonCashTitle)
  233.                <linecell symbols="-" />
  234.                       @GetAllTotalPrepayReturn(payments.ToList())
  235.                <linecell symbols="-" />
  236.            </cells>
  237.         </table>
  238.         <np />
  239.         <center>Без выручки</center>
  240.         <np />
  241.         <table>
  242.             <columns>
  243.                <column formatter="split" />
  244.                <column align="left" autowidth="" />
  245.                <column align="right" autowidth="" />
  246.             </columns>
  247.             <cells>
  248.                 <c colspan="3"></c>
  249.                 <linecell symbols="-" />
  250.                 <c>@Resources.PaymentType</c>
  251.                 <ct>@Resources.Cheques</ct>
  252.                 <ct>@Resources.Sum</ct>
  253.                 <linecell symbols="-" />
  254.  
  255.                  @GetWriteoff(payments.Where(p => p.PaymentType.Group == PaymentGroup.Writeoff).ToList())
  256.                  <linecell symbols="-" />
  257.                  @GetWriteoffTotal(payments.Where(p => p.PaymentType.Group == PaymentGroup.Writeoff).ToList())
  258.                  <linecell symbols="-" />
  259.             </cells>
  260.         </table>
  261.  
  262.  
  263. }
  264.  
  265. @* Создаёт разметку для подраздела Приняте предоплаты *@
  266. @helper GetPrepay(List<ClosedOrderPayment> closedPayments, string Pay)
  267. {
  268.     if (Pay == "ОПЛАЧЕНО ЗА НАЛИЧНЫЕ")
  269.     {
  270.         Pay = "Наличные";
  271.     }
  272.     if (Pay == "ВЫРУЧКА ПО КАРТАМ")
  273.     {
  274.         Pay = "Банковские карты";
  275.     }
  276.     if (Pay.Contains("БЕЗНАЛИЧН"))
  277.     {
  278.         Pay = "Безналичный расчет";
  279.     }
  280.     foreach (var closedPaymentsGroup in closedPayments.GroupBy(x => x.Timestamp.Date))
  281.     {    
  282.         foreach (var closedPayment in closedPaymentsGroup.OrderBy(x => x.Timestamp))
  283.         {                  
  284.             switch (closedPayment.CloseType)
  285.             {
  286.                 case OrderCloseType.Prepay:
  287.                 {
  288.                     <ct>@closedPayment.Order.Number</ct>
  289.                     <ct>@closedPayment.Order.TableNumber</ct>
  290.                     <ct>@Pay</ct>
  291.                     <ct>@FormatPrice(closedPayment.Sum)</ct>                          
  292.                     break;
  293.                 }
  294.             }
  295.         }
  296.     }
  297.    // @GetOperationTypesSummary(closedPayments)
  298. }
  299.  
  300. @* Создаёт разметку для подраздела Возврат предоплат *@
  301. @helper GetPrepayReturn(List<ClosedOrderPayment> closedPayments, string Pay)
  302. {
  303.     Pay = PayName(Pay);
  304.     foreach (var closedPaymentsGroup in closedPayments.GroupBy(x => x.Timestamp.Date))
  305.     {    
  306.         foreach (var closedPayment in closedPaymentsGroup.OrderBy(x => x.Timestamp))
  307.         {                  
  308.             switch (closedPayment.CloseType)
  309.             {          
  310.                 case OrderCloseType.PrepayReturn:
  311.                 {
  312.                     <ct>@closedPayment.Order.Number</ct>
  313.                     <ct>@closedPayment.Order.TableNumber</ct>
  314.                     <ct>@Pay</ct>
  315.                     <ct>@FormatPrice(closedPayment.Sum)</ct>
  316.             break;
  317.                 }
  318.             }
  319.         }
  320.     }
  321.  
  322.    
  323. }
  324.  
  325.  
  326. @* Возвращает итоги по Предоплатам внутри группы типов платежей (например, для группы платежей по банковским картам: MasterCard, Visa и т.п.) *@
  327. @helper GetTotalPrepay(IEnumerable<ClosedOrderPayment> closedPayments, string Pay)
  328. {  
  329.      Pay = PayName(Pay);      
  330.      foreach (var group in closedPayments.GroupBy(x => x.CloseType))
  331.      {
  332.          switch (group.Key)
  333.          {
  334.             case OrderCloseType.Prepay:
  335.             {
  336.                 <ct>@string.Format(Resources.TotalSub, Pay)</ct>
  337.                 <ct>@group.Count()</ct>
  338.                 <ct>@FormatPrice(group.Sum(x => x.Sum))</ct>
  339.                 break;
  340.              }
  341.          }
  342.      }
  343. }
  344.  
  345. @* Возвращает итоги по Предоплатам внутри группы типов платежей (например, для группы платежей по банковским картам: MasterCard, Visa и т.п.) *@
  346. @helper GetAllTotalPrepay(IEnumerable<ClosedOrderPayment> closedPayments)
  347. {  
  348.      //Pay = PayName(Pay);      
  349.      foreach (var group in closedPayments.GroupBy(x => x.CloseType))
  350.      {
  351.          switch (group.Key)
  352.          {
  353.             case OrderCloseType.Prepay:
  354.             {
  355.                 <ct>@string.Format(Resources.TotalSub, "Предоплат")</ct>
  356.                 <ct>@group.Count()</ct>
  357.                 <ct>@FormatPrice(group.Sum(x => x.Sum))</ct>
  358.                 break;
  359.              }
  360.          }
  361.      }
  362. }
  363.  
  364. @* Возвращает итоги по Предоплатам внутри группы типов платежей (например, для группы платежей по банковским картам: MasterCard, Visa и т.п.) *@
  365. @helper GetTotalPrepayReturn(IEnumerable<ClosedOrderPayment> closedPayments, string Pay)
  366. {  
  367.      Pay = PayName(Pay);      
  368.      foreach (var group in closedPayments.GroupBy(x => x.CloseType))
  369.      {
  370.          switch (group.Key)
  371.          {
  372.             case OrderCloseType.PrepayReturn:
  373.             {
  374.                 <ct>@string.Format(Resources.TotalSub, Pay)</ct>
  375.                 <ct>@group.Count()</ct>
  376.                 <ct>@FormatPrice(group.Sum(x => x.Sum))</ct>
  377.                 break;
  378.              }
  379.          }
  380.      }
  381. }
  382.  
  383. @* Возвращает итоги по Предоплатам внутри группы типов платежей (например, для группы платежей по банковским картам: MasterCard, Visa и т.п.) *@
  384. @helper GetAllTotalPrepayReturn(IEnumerable<ClosedOrderPayment> closedPayments)
  385. {  
  386.      //Pay = PayName(Pay);      
  387.      foreach (var group in closedPayments.GroupBy(x => x.CloseType))
  388.      {
  389.          switch (group.Key)
  390.          {
  391.             case OrderCloseType.PrepayReturn:
  392.             {
  393.                 <ct>@string.Format(Resources.TotalSub, "Предоплат")</ct>
  394.                 <ct>@group.Count()</ct>
  395.                 <ct>@FormatPrice(group.Sum(x => x.Sum))</ct>
  396.                 break;
  397.              }
  398.          }
  399.      }
  400. }
  401.  
  402.  
  403. @* Без выручки по типам *@
  404. @helper GetWriteoff(IEnumerable<ClosedOrderPayment> closedPayments)
  405. {  
  406.      //Pay = PayName(Pay);      
  407.      foreach (var group in closedPayments.GroupBy(x => x.PaymentType))
  408.      {
  409.                 <ct>@group.Key.Name</ct>
  410.                 <ct>@group.Count()</ct>
  411.                 <ct>@FormatPrice(group.Sum(x => x.Sum))</ct>
  412.      }
  413. }
  414.  
  415. @* Без выручки (все) *@
  416. @helper GetWriteoffTotal(IEnumerable<ClosedOrderPayment> closedPayments)
  417. {  
  418.      //Pay = PayName(Pay);      
  419.      foreach (var group in closedPayments.GroupBy(x => x.CloseType))
  420.      {
  421.                 <ct>@string.Format(Resources.TotalSub, "Без выручки")</ct>
  422.                 <ct>@group.Count()</ct>
  423.                 <ct>@FormatPrice(group.Sum(x => x.Sum))</ct>
  424.      }
  425. }
  426.  
  427. @functions
  428. {
  429.     private SortedDictionary<bool, Dictionary<PaymentGroup, List<DetailedSaleInfo>>> salesData;
  430.     private IEnumerable<TaxInfo> taxesData;
  431.     private int totalChequesNum;
  432.    
  433.     private IEnumerable<ClosedOrder> closedOrdersSource;
  434.  
  435.     /// <summary>
  436.     /// Заполнение данных о всех оплатах
  437.     /// </summary>
  438.     private void FillData()
  439.     {
  440.         var session = Model.CafeSession;
  441.         if (session == null)
  442.             return;
  443.  
  444.         // получить все транзакции оплаты, сгруппированные по заказам
  445.         var transactions = Model.Transactions.GetOrderPaymentTransactionsBySession(session)
  446.             .Where(tr => tr.Order != null)
  447.             .GroupBy(tr => tr.Order)
  448.             .ToDictionary(g => g.Key, g => (ICollection<IOrderPaymentTransaction>)g.ToArray());
  449.  
  450.         closedOrdersSource = session.ClosedOrders
  451.             .Concat(session.StornedOrders)
  452.             .Except(transactions.Keys)
  453.             .Select(order => new ClosedOrder(order, new IOrderPaymentTransaction[0]))
  454.             .Concat(transactions.Select(tr => new ClosedOrder(tr.Key, tr.Value)))
  455.             .ToList();
  456.     }
  457.    
  458.     public sealed class ClosedOrder
  459.     {
  460.         public readonly int Number;
  461.         public readonly int TableNumber;
  462.         public readonly string WaiterName;
  463.        
  464.         /// <summary>
  465.         /// Оплаты (включая предоплаты)
  466.         /// </summary>
  467.         public readonly List<ClosedOrderPayment> Payments;
  468.        
  469.         /// <summary>
  470.         /// Скидки и надбавки
  471.         /// </summary>
  472.         public readonly List<ClosedOrderDiscountItem> Discounts;
  473.        
  474.         /// <summary>
  475.         /// Оплаченные элементы заказа
  476.         /// </summary>
  477.         public readonly List<OrderItem> Items;
  478.        
  479.         public ClosedOrder(IOrder order, ICollection<IOrderPaymentTransaction> transactions)
  480.         {
  481.             Number = order.Number;
  482.             TableNumber = order.Table.Number;
  483.             WaiterName = order.Waiter == null ? null : order.Waiter.Name;
  484.             Payments = BuildClosedOrderPaymentList(order, transactions).ToList();
  485.             Discounts = order.DiscountItems.Select(item => new ClosedOrderDiscountItem(item, order.GetFullSum())).ToList();
  486.             Items = order.GetIncludedEntries().Select(item => new OrderItem(item, order)).ToList();
  487.         }
  488.  
  489.         private IEnumerable<ClosedOrderPayment> BuildClosedOrderPaymentList(IOrder baseOrder, ICollection<IOrderPaymentTransaction> transactions)
  490.         {
  491.             var closedOrderPayments = new List<ClosedOrderPayment>();
  492.  
  493.             var prepays = transactions.OfType<IOrderPrepayTransaction>().Where(tr => tr.TransactionType == OrderPaymentTransactionType.Prepay);
  494.             closedOrderPayments.AddRange(prepays.Select(tr => new ClosedOrderPayment(tr, ParseCloseType(tr, baseOrder), this)));
  495.             var returnPrepays = transactions.OfType<IOrderPrepayTransaction>().Where(tr => tr.TransactionType == OrderPaymentTransactionType.PrepayReturn);
  496.             closedOrderPayments.AddRange(returnPrepays.Select(tr => new ClosedOrderPayment(tr, ParseCloseType(tr, baseOrder), this)));
  497.  
  498.             var payments = transactions.Where(tr => !(tr is IOrderPrepayTransaction) && !(tr is IOrderPrepayClosedTransaction));
  499.             closedOrderPayments.AddRange(payments.Select(tr => new ClosedOrderPayment(tr, ParseCloseType(tr, baseOrder), this)));
  500.  
  501.             if (baseOrder.CloseInfo == null || baseOrder.CloseInfo.WriteoffItem == null)
  502.                 return closedOrderPayments;
  503.    
  504.             // создать фейковую транзакцию для типа оплаты "Без выручки" и добавить в список
  505.             var fakeTransaction = new FakeWriteoffPaymentTransactionForReport(baseOrder.CloseInfo.WriteoffItem, baseOrder.CloseInfo, false);
  506.             closedOrderPayments.Add(new ClosedOrderPayment(fakeTransaction, ParseCloseType(fakeTransaction, baseOrder), this));
  507.  
  508.             // создать фейковую транзакцию для сторнированного заказа (показывать с отриц.суммами) с типом оплаты "Без выручки" и добавить в список
  509.             if (baseOrder.Status == OrderStatus.Deleted)
  510.             {
  511.                 fakeTransaction = new FakeWriteoffPaymentTransactionForReport(baseOrder.CloseInfo.WriteoffItem, baseOrder.CloseInfo, true);
  512.                 closedOrderPayments.Add(new ClosedOrderPayment(fakeTransaction, ParseCloseType(fakeTransaction, baseOrder), this));
  513.             }
  514.  
  515.             return closedOrderPayments;
  516.         }
  517.     }
  518.  
  519.     public sealed class ClosedOrderPayment
  520.     {
  521.         public readonly IPaymentType PaymentType;
  522.        
  523.         /// <summary>
  524.         /// Номер платёжной банковской карты для типа оплаты "Банковские карты".
  525.         /// Во фронте нет возможности узнать номер платёжной банковской карты
  526.         /// </summary>
  527.         public readonly string CardNumber = string.Empty;
  528.        
  529.         /// <summary>
  530.         /// Контрагент для типа оплаты "В кредит"
  531.         /// </summary>
  532.         public readonly string CreditUserName;
  533.        
  534.         /// <summary>
  535.         /// Карта контрагента для типа оплаты "В кредит"
  536.         /// </summary>
  537.         public readonly string CreditUserMaskedCardNumber;
  538.        
  539.         /// <summary>
  540.         /// Причина оплаты "За счет заведения" (Без выручки)
  541.         /// </summary>
  542.         public readonly string WriteoffReason;
  543.        
  544.         /// <summary>
  545.         /// Кассир
  546.         /// </summary>
  547.         public readonly string CashierName;
  548.  
  549.         /// <summary>
  550.         /// Кем авторизована транзакция оплаты
  551.         /// </summary>
  552.         public readonly string AuthUserName;
  553.        
  554.         /// <summary>
  555.         /// Родительский заказ
  556.         /// </summary>
  557.         public readonly ClosedOrder Order;
  558.  
  559.         public readonly OrderCloseType CloseType;
  560.         public readonly decimal Sum;
  561.         public readonly DateTime Timestamp;
  562.  
  563.         public ClosedOrderPayment(IOrderPaymentTransaction paymentTransaction, OrderCloseType closeType, ClosedOrder closedOrder)
  564.         {
  565.             PaymentType = paymentTransaction.PaymentType;
  566.             CloseType = closeType;
  567.             Sum = paymentTransaction.Sum;
  568.             Timestamp = paymentTransaction.Date;
  569.             CashierName = paymentTransaction.Cashier.Name;
  570.             Order = closedOrder;
  571.            
  572.             // Если это транзакции оплаты "В кредит"
  573.             var creditTransaction = paymentTransaction as ICreditPaymentTransaction;
  574.             if (creditTransaction != null && creditTransaction.Counteragent != null)
  575.             {
  576.                 CreditUserName = creditTransaction.Counteragent.Name;
  577.                 if (creditTransaction.CreditCounteragentCardSlided && !string.IsNullOrEmpty(creditTransaction.Counteragent.Card))
  578.                     CreditUserMaskedCardNumber = MaskCardNumber(creditTransaction.Counteragent.Card, 3);
  579.             }
  580.  
  581.             // Если это транзакция оплаты "Без выручки", заполняем причину списания
  582.             // Иначе заполняем юзера, который подтвердил оплату
  583.             //var writeoffPaymentTransaction = paymentTransaction as FakeWriteoffPaymentTransactionForReport;
  584.            
  585.         }
  586.     }
  587.  
  588.     private sealed class FakeWriteoffPaymentTransactionForReport : IOrderPaymentTransaction
  589.     {
  590.         private readonly IWriteoffPaymentItem paymentItem;
  591.         private readonly IOrderCloseInfo closeInfo;
  592.         private readonly bool isViewOrderAsStorned;
  593.  
  594.         public FakeWriteoffPaymentTransactionForReport(IWriteoffPaymentItem paymentItem, IOrderCloseInfo closeInfo, bool isViewOrderAsStorned)
  595.         {
  596.             this.paymentItem = paymentItem;
  597.             this.closeInfo = closeInfo;
  598.             this.isViewOrderAsStorned = isViewOrderAsStorned;
  599.         }
  600.        
  601.         // Время закрытия заказа, но проставляется и как время оплаты, и как время сторнирования
  602.        
  603.         public DateTime Date
  604.         {
  605.             get { throw new NotSupportedException(); }
  606.         }
  607.  
  608.         public decimal Sum
  609.         {
  610.             get { return isViewOrderAsStorned ? -paymentItem.Sum : paymentItem.Sum; }
  611.         }
  612.  
  613.         public bool IsFiscal
  614.         {
  615.             get { throw new NotSupportedException(); }
  616.         }
  617.  
  618.         public IOrder Order
  619.         {
  620.             get { throw new NotSupportedException(); }
  621.         }
  622.  
  623.         public IUser Cashier
  624.         {
  625.             get { throw new NotSupportedException(); }
  626.         }
  627.  
  628.         public IPaymentType PaymentType
  629.         {
  630.             get { return paymentItem.Type; }
  631.         }
  632.  
  633.         public OrderPaymentTransactionType TransactionType
  634.         {
  635.             get { return OrderPaymentTransactionType.OnTheHouse; }
  636.         }
  637.  
  638.         public int ChequeNumber
  639.         {
  640.             get { throw new NotSupportedException(); }
  641.         }
  642.  
  643.         public bool IsPurchase
  644.         {
  645.             get { throw new NotSupportedException(); }
  646.         }
  647.  
  648.         public IAuthData AuthData
  649.         {
  650.             get { throw new NotSupportedException(); }
  651.         }
  652.  
  653.         public bool IsWaiterDebt
  654.         {
  655.             get { throw new NotSupportedException(); }
  656.         }
  657.  
  658.         public ICurrencyInfo CurrencyInfo
  659.         {
  660.             get { throw new NotImplementedException(); }
  661.         }
  662.  
  663.         public Guid OrderId
  664.         {
  665.             get { throw new NotImplementedException(); }
  666.         }
  667.        
  668.         public bool IsDeliveryOrder
  669.         {
  670.             get { throw new NotImplementedException(); }
  671.         }
  672.        
  673.     }
  674.  
  675.     public sealed class ClosedOrderDiscountItem
  676.     {
  677.         /// <summary>
  678.         /// Тип скидки или надбавки
  679.         /// </summary>
  680.         public readonly string DiscountTypeName;
  681.  
  682.         /// <summary>
  683.         /// Процент скидки или надбавки
  684.         /// </summary>
  685.         public readonly decimal DiscountPercent;
  686.  
  687.         /// <summary>
  688.         /// Кем авторизована скидка
  689.         /// </summary>
  690.         public readonly string AuthUserName;
  691.        
  692.         /// <summary>
  693.         /// Имя гостя, если скидка по карте
  694.         /// </summary>
  695.         public readonly string GuestName;
  696.  
  697.         /// <summary>
  698.         /// Трек гостевой катры, если скидка по карте
  699.         /// </summary>
  700.         public readonly string GuestCardTrack;
  701.  
  702.         /// <summary>
  703.         /// Является ли скидка автоматической
  704.         /// </summary>
  705.         public readonly bool IsAutomatic;
  706.  
  707.         /// <summary>
  708.         /// Является ли скидка скидкой на категорию
  709.         /// </summary>
  710.         public readonly bool IsCategorised;
  711.  
  712.         /// <summary>
  713.         /// Количество отображаемых и печатаемых цифр номера карты, если скидка по карте
  714.         /// </summary>
  715.         private readonly int? visibleDigitsCount;
  716.         public int VisibleDigitsCount
  717.         {
  718.             get
  719.             {
  720.                 if (!visibleDigitsCount.HasValue)
  721.                     throw new NotSupportedException();
  722.                 return visibleDigitsCount.Value;
  723.             }
  724.         }
  725.  
  726.         public ClosedOrderDiscountItem(IDiscountItem item, decimal orderSum)
  727.         {
  728.             IsAutomatic = item.Source == DiscountSource.Auto;
  729.             DiscountPercent = ModelExtensions.CalculateDiscountPercent(orderSum, item.GetDiscountSum());
  730.             DiscountTypeName = item.Type.Name;
  731.             IsCategorised = item.IsCategorized;
  732.             AuthUserName = item.AuthData != null ? item.AuthData.User.Name : null;
  733.            
  734.             if (item.CardInfo == null)
  735.                 return;
  736.            
  737.             visibleDigitsCount = item.NumOfPrintedDigits;
  738.             GuestCardTrack = item.CardInfo.Card;
  739.             GuestName = item.CardInfo.Owner;
  740.         }
  741.     }
  742.    
  743.  
  744.     /// <summary>
  745.     /// Отдельная позиция закрытого заказа (блюдо)
  746.     /// </summary>
  747.     public sealed class OrderItem
  748.     {
  749.         public readonly string Name;
  750.         public readonly decimal Amount;
  751.         public readonly decimal Sum;
  752.  
  753.         public OrderItem(IOrderEntry baseOrderItem, IOrder order)
  754.         {
  755.             Amount = baseOrderItem.Amount;
  756.             Name = baseOrderItem.Product.Name;
  757.             Sum = baseOrderItem.GetVatSumExcludedFromPriceForOrderEntry(order.DiscountItems) + baseOrderItem.GetCost();
  758.         }
  759.     }
  760.    
  761.     public enum OrderCloseType
  762.     {
  763.         /// <summary>
  764.         /// Продажа
  765.         /// </summary>
  766.         Sale,
  767.         /// <summary>
  768.         /// Возврат заказа
  769.         /// </summary>
  770.         Storno,
  771.         /// <summary>
  772.         /// Внесение предоплаты
  773.         /// </summary>
  774.         Prepay,
  775.         /// <summary>
  776.         /// Возврат предоплаты
  777.         /// </summary>
  778.         PrepayReturn
  779.     };
  780.    
  781.     private static OrderCloseType ParseCloseType(IOrderPaymentTransaction transaction, IOrder baseOrder)
  782.     {
  783.         switch (transaction.TransactionType)
  784.         {
  785.             case OrderPaymentTransactionType.Cash:
  786.             case OrderPaymentTransactionType.Card:
  787.             case OrderPaymentTransactionType.Credit:
  788.             case OrderPaymentTransactionType.OnTheHouse:
  789.             {
  790.                 // Если заказ сторнирован и показывается с отрицательной суммой, присваиваем OrderCloseType = Storno.
  791.                 // Все потому что для сторнирования не предусмотрен отдельный тип транзакции,
  792.                 // поэтому различаем сторнирование от продажи с помощью знаков суммы транзакции
  793.                 return baseOrder.Status == OrderStatus.Deleted
  794.                     ? transaction.Sum > 0
  795.                         ? OrderCloseType.Sale
  796.                         : OrderCloseType.Storno
  797.                     : OrderCloseType.Sale;
  798.             }
  799.             case OrderPaymentTransactionType.Prepay:
  800.                 return OrderCloseType.Prepay;
  801.             case OrderPaymentTransactionType.PrepayReturn:
  802.                 return OrderCloseType.PrepayReturn;
  803.             default:
  804.                 throw new NotSupportedException();
  805.         }
  806.     }
  807.  
  808.     private static string PayName(string Pay)
  809.     {
  810.        if (Pay == "ОПЛАЧЕНО ЗА НАЛИЧНЫЕ")
  811.        {
  812.           Pay = "Наличные";
  813.        }
  814.        if (Pay == "ВЫРУЧКА ПО КАРТАМ")
  815.        {
  816.           Pay = "Банковские карты";
  817.        }
  818.        if (Pay.Contains("БЕЗНАЛИЧНЫ"))
  819.        {
  820.           Pay = "Безналичный расчет";
  821.        }
  822.        return Pay;
  823.     }
  824.    
  825.     /// <summary>
  826.     /// Возвращает название операции (для заголовка, в единственном числе)
  827.     /// </summary>
  828.     private static string GetOrderCloseTypeName(OrderCloseType closeType)
  829.     {
  830.         switch (closeType)
  831.         {
  832.             case OrderCloseType.Sale:
  833.                 return Resources.OrderCloseTypeSell;
  834.             case OrderCloseType.Prepay:
  835.                 return Resources.OrderCloseTypePrepay;
  836.             case OrderCloseType.Storno:
  837.                 return Resources.OrderCloseTypeStorno;
  838.             case OrderCloseType.PrepayReturn:
  839.                 return Resources.OrderCloseTypePrepayReturn;
  840.             default:
  841.                 throw new ArgumentOutOfRangeException("closeType");
  842.         }
  843.     }
  844.  
  845.     /// <summary>
  846.     /// Возвращает название операции (для итогов, во множественном числе)
  847.     /// </summary>
  848.     private static string GetOrderCloseTypeSummaryName(OrderCloseType closeType)
  849.     {
  850.         switch (closeType)
  851.         {
  852.             case OrderCloseType.Sale:
  853.                 return Resources.OrderCloseTypeSummarySell;
  854.             case OrderCloseType.Prepay:
  855.                 return Resources.OrderCloseTypeSummaryPrepay;
  856.             case OrderCloseType.Storno:
  857.                 return Resources.OrderCloseTypeSummaryStorno;
  858.             case OrderCloseType.PrepayReturn:
  859.                 return Resources.OrderCloseTypeSummaryPrepayReturn;
  860.             default:
  861.                 throw new ArgumentOutOfRangeException("closeType");
  862.         }
  863.     }
  864.    
  865.     private static IWriteoffPaymentType GetWriteoffPaymentType(IPaymentType paymentType)
  866.     {
  867.         var cpt = paymentType as IConfigurablePaymentType;
  868.         if (cpt != null)
  869.             paymentType = cpt.BasePaymentType;
  870.         return (IWriteoffPaymentType)paymentType;
  871.     }
  872.  
  873.     private static bool IsCreditPaymentType(IPaymentType paymentType)
  874.     {
  875.         var cpt = paymentType as IConfigurablePaymentType;
  876.         if (cpt != null)
  877.             paymentType = cpt.BasePaymentType;
  878.         return paymentType is ICreditPaymentType;
  879.     }
  880.  
  881.     private static string MaskCardNumber(string cardTrack, int visibleDigitsCount)
  882.     {
  883.         if (string.IsNullOrEmpty(cardTrack))
  884.             throw new ArgumentException("Card track must contain at least one digit", "cardTrack");
  885.  
  886.         if (visibleDigitsCount < 0)
  887.             throw new ArgumentOutOfRangeException("visibleDigitsCount", "Visible digits count must be greater than or equal to zero.");
  888.  
  889.         if (visibleDigitsCount == 0)
  890.             return string.Empty;
  891.        
  892.         return cardTrack.Length > visibleDigitsCount
  893.             ? string.Format(Resources.GuestCardMaskFormat, cardTrack.Substring(cardTrack.Length - visibleDigitsCount))
  894.             : string.Format(Resources.GuestCardFormat, cardTrack);
  895.     }
  896.  
  897.     private sealed class SaleInfo
  898.     {
  899.         public bool IsFiscal { get; set; }
  900.         public PaymentGroup PaymentGroup { get; set; }
  901.         public DetailedSaleInfo DetailedSaleInfo { get; set; }
  902.     }
  903.  
  904.     private sealed class DetailedSaleInfo
  905.     {
  906.         public string PaymentTypeName { get; set; }
  907.         public int ChequesNum { get; set; }
  908.         public decimal Sum { get; set; }
  909.     }
  910.  
  911.     private sealed class TaxInfo
  912.     {
  913.         public decimal VatPercent { get; set; }
  914.         public decimal VatSum { get; set; }
  915.         public decimal Sum { get; set; }
  916.     }
  917.  
  918.     /// <summary>
  919.     /// Заполнение данных о фискальных/нефискальных оплатах
  920.     /// </summary>
  921.     private void FillSalesData()
  922.     {
  923.         var session = Model.CafeSession;
  924.         if (session == null)
  925.             return;
  926.        
  927.         var transactionsBySession = Model.Transactions.GetOrderPaymentTransactionsBySession(session)
  928.             // Предоплаты учитываем только после оплаты заказа и не учитываем сторнированные заказы
  929.             .Where(pt => !(pt is IOrderPrepayTransaction) && (pt.Order == null || !pt.Order.IsStorned))
  930.             .ToList();
  931.  
  932.         // Группировка по фиск./нефиск. типам, потом по группам оплаты, где у каждой группы оплаты есть список DetailedSaleInfo (тип оплаты с количеством заказов и суммой)
  933.         var sales = transactionsBySession
  934.             .GroupBy(t => t.PaymentType)
  935.             .Select(data => new SaleInfo
  936.             {
  937.                 IsFiscal = data.Key.PrintCheque,
  938.                 PaymentGroup = data.Key.Group,
  939.                
  940.                 DetailedSaleInfo = new DetailedSaleInfo
  941.                 {
  942.                     PaymentTypeName = data.Key.Name,
  943.                     Sum = data.Sum(t => t.Sum),
  944.                     ChequesNum = data.Select(t => t.Order).Distinct().Count()
  945.                 }
  946.             })
  947.             .GroupBy(sale => sale.IsFiscal)
  948.             .ToDictionary(fiscalGroup => fiscalGroup.Key, fiscalGroup => fiscalGroup
  949.                 .GroupBy(sale => sale.PaymentGroup)
  950.                 .ToDictionary(paymentGroupGroup => paymentGroupGroup.Key, paymentGroupGroup => paymentGroupGroup
  951.                     .Select(info => info.DetailedSaleInfo)
  952.                     .OrderBy(info => info.PaymentTypeName)
  953.                     .ToList()));
  954.  
  955.         if (!sales.ContainsKey(true))
  956.             sales.Add(true, new Dictionary<PaymentGroup, List<DetailedSaleInfo>>());
  957.         if (!sales.ContainsKey(false))
  958.             sales.Add(false, new Dictionary<PaymentGroup, List<DetailedSaleInfo>>());
  959.  
  960.         salesData = new SortedDictionary<bool, Dictionary<PaymentGroup, List<DetailedSaleInfo>>>(sales, new DescendingComparer<bool>());
  961.         totalChequesNum = transactionsBySession.Select(t => t.Order).Distinct().Count();
  962.     }
  963.    
  964.    
  965.  
  966.     private sealed class DescendingComparer<T> : IComparer<T> where T : IComparable<T>
  967.     {
  968.         public int Compare(T x, T y)
  969.         {
  970.             return y.CompareTo(x);
  971.         }
  972.     }
  973. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement