public async Task CancelOrder(int id)
        {
            await StatusService.CheckRightsForOrderAddDelete();

            await ModifyOrder(id, new StatusModModel()
            {
                Status = nameof(OrderStatus.Cancelled)
            });
        }
        public async Task <OrderDataModel> GetOrderDetails(int id)
        {
            var order = await DbContext.Orders
                        .Include(o => o.OrderSession)
                        .ThenInclude(os => os.Table)
                        .Include(o => o.OrderSession.Customer)
                        .Include(o => o.Waiter)
                        .Include(o => o.Items)
                        .ThenInclude(oi => oi.MenuItem)
                        .ThenInclude(mi => mi.Category)
                        .Where(o => o.Id == id).SingleOrDefaultAsync();

            if (order == null)
            {
                throw new RestaurantNotFoundException("Nem létező rendelés!");
            }

            await StatusService.CheckRightsForStatus(order.OrderSession.Status, order.Status);

            List <OrderItemListModel> items = new List <OrderItemListModel>();

            order.Items.ForEach(oi =>
            {
                items.Add(new OrderItemListModel()
                {
                    OrderItemId          = oi.Id,
                    MenuItemId           = oi.MenuItemId,
                    Name                 = oi.MenuItem.Name,
                    Quantity             = oi.Quantity,
                    Price                = oi.MenuItem.Price,
                    Comment              = oi.Comment,
                    MenuItemCategoryId   = oi.MenuItem.CategoryId,
                    MenuItemCategoryName = oi.MenuItem.Category.Name
                });
            });

            return(new OrderDataModel()
            {
                Id = order.Id,
                OrderSessionId = order.OrderSessionId,
                WaiterId = order.WaiterUserId,
                WaiterName = order.Waiter.Name,
                TableId = order.OrderSession.TableId,
                TableCode = order.OrderSession.Table?.Code,
                CustomerId = order.OrderSession.CustomerId,
                CustomerName = order.OrderSession.Customer?.Name,
                CustomerPhoneNumber = order.OrderSession.Customer?.PhoneNumber,
                CustomerAddress = order.OrderSession.Customer?.Address,
                Status = Enum.GetName(typeof(OrderStatus), order.Status),
                OpenedAt = order.OpenedAt,
                ClosedAt = order.ClosedAt,
                Price = order.CalculatePrice(),
                Items = items
            });
        }
        public async Task <OrderSessionDataModel> GetOrderSessionDetails(int id)
        {
            var orderSession = await DbContext.OrderSessions
                               .Include(os => os.Customer)
                               .Include(os => os.Voucher)
                               .Include(os => os.Table)
                               .Include(os => os.Orders)
                               .ThenInclude(o => o.Items)
                               .ThenInclude(oi => oi.MenuItem)
                               .Where(os => os.Id == id).SingleOrDefaultAsync();

            if (orderSession == null)
            {
                throw new RestaurantNotFoundException("Nem létező rendelési folyamat!");
            }

            await StatusService.CheckRightsForStatus(orderSession.Status);

            var orders = new List <OrderListModel>();

            orderSession.Orders.ForEach(order =>
            {
                orders.Add(new OrderListModel()
                {
                    Id       = order.Id,
                    WaiterId = order.WaiterUserId,
                    Status   = Enum.GetName(typeof(OrderStatus), order.Status),
                    OpenedAt = order.OpenedAt,
                    ClosedAt = order.ClosedAt,
                    Price    = order.CalculatePrice()
                });
            });

            return(new OrderSessionDataModel()
            {
                Id = orderSession.Id,
                TableId = orderSession.TableId,
                TableCode = orderSession.Table?.Code,
                CustomerId = orderSession.CustomerId,
                CustomerName = orderSession.Customer?.Name,
                CustomerPhoneNumber = orderSession.Customer?.PhoneNumber,
                CustomerAddress = orderSession.Customer?.Address,
                VoucherId = orderSession.VoucherId,
                VoucherCode = orderSession.Voucher?.Code,
                VoucherDiscountPercentage = orderSession.Voucher?.DiscountPercentage,
                VoucherDiscountAmount = orderSession.Voucher?.DiscountAmount,
                InvoiceId = orderSession.InvoiceId,
                Status = Enum.GetName(typeof(OrderSessionStatus), orderSession.Status),
                OpenedAt = orderSession.OpenedAt,
                ClosedAt = orderSession.ClosedAt,
                FullPrice = CalculatePrice(orderSession),
                Orders = orders
            });
        }
        public async Task <OrderSessionPayResultModel> PayOrders(int id, OrderSessionPayModel model)
        {
            if (!Enum.IsDefined(typeof(PaymentMethod), model.PaymentMethod))
            {
                throw new RestaurantNotFoundException("Nem létező fizetési mód!");
            }

            var orderSession = await DbContext.OrderSessions.Include(os => os.Orders)
                               .ThenInclude(o => o.Items)
                               .ThenInclude(oi => oi.MenuItem)
                               .Where(os => os.Id == id && (os.Status == OrderSessionStatus.Active || os.Status == OrderSessionStatus.Delivering))
                               .SingleOrDefaultAsync();

            if (orderSession == null)
            {
                throw new RestaurantNotFoundException("A rendelési folyamat nem létezik vagy a fizetése nem lehetséges!");
            }

            await StatusService.CheckRightsForStatus(orderSession.Status);

            var summary = await GetPaymentSummary(orderSession, model);

            //Generate invoice
            var invoiceModel = new InvoiceCreationModel()
            {
                FullPrice             = summary.FullPrice,
                FinalPrice            = summary.FinalPrice,
                VoucherCode           = model.VoucherCode,
                VoucherDiscountAmount = summary.VoucherTotalDiscountAmount,
                RedeemedLoyaltyPoints = summary.UsedLoyaltyPoints ?? 0,
                CustomerName          = model.CustomerName,
                CustomerTaxNumber     = model.CustomerTaxNumber,
                CustomerAddress       = model.CustomerAddress,
                CustomerPhoneNumber   = model.CustomerPhoneNumber,
                CustomerEmail         = model.CustomerEmail,
                PaymentMethod         = model.PaymentMethod,
                OrderSession          = orderSession
            };

            var invoiceId = await InvoiceService.CreateInvoice(invoiceModel);

            orderSession.InvoiceId = invoiceId;

            //Close order
            orderSession.Status   = OrderSessionStatus.Paid;
            orderSession.ClosedAt = DateTime.Now;

            await DbContext.SaveChangesAsync();

            return(new OrderSessionPayResultModel()
            {
                InvoiceId = invoiceId
            });                                                                              //Invoice id
        }
        public async Task <OrderSessionPaySummaryModel> GetPaymentSummary(int orderSessionId, OrderSessionPaySummaryRequestModel model)
        {
            var orderSession = await DbContext.OrderSessions.Include(os => os.Orders)
                               .ThenInclude(o => o.Items)
                               .ThenInclude(oi => oi.MenuItem)
                               .Where(os => os.Id == orderSessionId && (os.Status == OrderSessionStatus.Active || os.Status == OrderSessionStatus.Delivering))
                               .SingleOrDefaultAsync();

            if (orderSession == null)
            {
                throw new RestaurantNotFoundException("A rendelési folyamat nem létezik vagy a fizetése nem lehetséges!");
            }

            await StatusService.CheckRightsForStatus(orderSession.Status);

            return(await GetPaymentSummary(orderSession, model));
        }
        public async Task RemoveOrderItem(int orderId, int itemId)
        {
            var order = await DbContext.Orders
                        .Include(o => o.OrderSession)
                        .Include(o => o.Items)
                        .Where(o => o.Id == orderId && o.Status == OrderStatus.Ordering && o.OrderSession.Status == OrderSessionStatus.Active)
                        .SingleOrDefaultAsync();

            if (order == null)
            {
                throw new RestaurantNotFoundException("A rendelés nem létezik vagy nem lehetséges a módosítása!");
            }

            await StatusService.CheckRightsForStatus(order.OrderSession.Status, order.Status);

            DbContext.OrderItems.Remove(order.Items.Find(oi => oi.Id == itemId));

            await DbContext.SaveChangesAsync();
        }
        public async Task <AddResult> AddOrder(OrderAddModel model)
        {
            if (model.TableId == null && model.CustomerId == null)
            {
                throw new RestaurantBadRequestException("Asztal/kiszállítási adatok nélküli rendelés nem vehető fel!");
            }

            var waiter = await DbContext.Users.FindAsync(model.WaiterId);

            if (waiter == null)
            {
                throw new RestaurantNotFoundException("A megadott pincér nem létezik!");
            }

            await StatusService.CheckRightsForOrderAddDelete();

            OrderSession orderSession = null;

            if (model.TableId != null)
            {
                orderSession = await DbContext.OrderSessions.Where(os => os.TableId == model.TableId && os.Status == OrderSessionStatus.Active).SingleOrDefaultAsync();
            }

            if (orderSession == null)
            {
                orderSession = await OrderSessionService.CreateNewSession(model);
            }

            var order = DbContext.Orders.Add(new Order()
            {
                WaiterUserId   = model.WaiterId,
                Status         = OrderStatus.Ordering,
                OrderSessionId = orderSession.Id,
                OpenedAt       = DateTime.Now
            });

            await DbContext.SaveChangesAsync();

            return(new AddResult(order.Entity.Id));
        }
        public async Task <AddResult> AddOrderItem(int orderId, OrderItemAddModel model)
        {
            if (model.Quantity < 1)
            {
                throw new RestaurantBadRequestException("A mennyiségnek pozitív számnak kell lennie!");
            }

            var menuItem = await DbContext.MenuItems.FindAsync(model.MenuItemId);

            if (menuItem == null)
            {
                throw new RestaurantNotFoundException("A megadott étel/ital nem létezik!");
            }

            var order = await DbContext.Orders.Include(o => o.OrderSession)
                        .Where(o => o.Id == orderId && o.Status == OrderStatus.Ordering && o.OrderSession.Status == OrderSessionStatus.Active)
                        .SingleOrDefaultAsync();

            if (order == null)
            {
                throw new RestaurantNotFoundException("A rendelés nem létezik vagy nem lehetséges új tételek hozzáadása!");
            }

            await StatusService.CheckRightsForStatus(order.OrderSession.Status, order.Status);

            var orderItem = DbContext.OrderItems.Add(new OrderItem()
            {
                OrderId    = orderId,
                MenuItemId = model.MenuItemId,
                Quantity   = model.Quantity,
                Comment    = model.Comment
            });

            await DbContext.SaveChangesAsync();

            return(new AddResult(orderItem.Entity.Id));
        }