public static List <CapitalPriceTrackingDto> UpdateCapitalPriceTracking(int updatedIndex,
                                                                                CapitalPriceTrackingDto updatedCapitalPriceTrackingDto,
                                                                                List <CapitalPriceTrackingDto> capitalPriceTrackings)
        {
            capitalPriceTrackings[updatedIndex].Amount       = updatedCapitalPriceTrackingDto.Amount;
            capitalPriceTrackings[updatedIndex].Inventory    = updatedCapitalPriceTrackingDto.Inventory;
            capitalPriceTrackings[updatedIndex].CapitalPrice = updatedCapitalPriceTrackingDto.CapitalPrice;
            capitalPriceTrackings[updatedIndex].InputPrice   = updatedCapitalPriceTrackingDto.InputPrice;

            for (int i = updatedIndex + 1; i < capitalPriceTrackings.Count; i++)
            {
                int previousIndex = i - 1;
                {
                    if (capitalPriceTrackings[i].WarehousingId != Guid.Empty) // warehousing record
                    {
                        capitalPriceTrackings[i].Inventory    = capitalPriceTrackings[previousIndex].Inventory + capitalPriceTrackings[i].Amount;
                        capitalPriceTrackings[i].CapitalPrice = CalculateCapitalPrice(
                            capitalPriceTrackings[previousIndex].Inventory,
                            capitalPriceTrackings[previousIndex].CapitalPrice,
                            capitalPriceTrackings[i].Amount,
                            capitalPriceTrackings[i].InputPrice
                            );
                    }
                    else if (capitalPriceTrackings[i].BillId != Guid.Empty)// Bill record
                    {
                        capitalPriceTrackings[i].CapitalPrice = capitalPriceTrackings[previousIndex].CapitalPrice;
                        capitalPriceTrackings[i].Inventory    = capitalPriceTrackings[previousIndex].Inventory - capitalPriceTrackings[i].Amount;
                    }
                }
            }

            return(capitalPriceTrackings);
        }
        private void _addCapitalTracking(ProductForWareshousingCreationDto product, Guid storageId, Guid warehousingId, ProductStorageEntity productStorage)
        {
            // create capital price tracking
            productStorage.CapitalPrice = ProductStorageHelper.CalculateCapitalPrice(
                productStorage.Inventory, productStorage.CapitalPrice, product.InputAmount, product.InputPrice
                );

            productStorage.Inventory += product.InputAmount;

            CapitalPriceTrackingDto capitalPriceTracking = new CapitalPriceTrackingDto
            {
                WarehousingId = warehousingId,
                Amount        = product.InputAmount,
                InputPrice    = product.InputPrice,
                CapitalPrice  = productStorage.CapitalPrice,
                Inventory     = productStorage.Inventory
            };

            productStorage.CapitalPriceTrackings = productStorage.CapitalPriceTrackings ?? "[]";

            var capitalPriceTrackings = JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);

            capitalPriceTrackings.Add(capitalPriceTracking);
            productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);
            _context.ProductStorages.Update(productStorage);
        }
        private void _updateCapitalTrackingCapitalPriceAndInventory(ProductStorageEntity productStorage, ProductForBillCreationDto product, double newAmount, Guid billId)
        {
            // update capital price with average
            if (productStorage.CapitalPriceTrackings == null)
            {
                throw new Exception("CapitalPriceTrackings is NULL with ProductStorage.Id=" + productStorage.Id);
            }
            var capitalPriceTrackings = JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);

            var startedIndex = capitalPriceTrackings.FindIndex(c => c.BillId == billId);

            if (startedIndex < 0) // product is new on bill, we need to create a new tracking
            {
                var newCapitalPriceTrackingDto = new CapitalPriceTrackingDto()
                {
                    BillId       = billId,
                    Amount       = newAmount,
                    CapitalPrice = productStorage.CapitalPrice,
                    Inventory    = productStorage.Inventory - newAmount
                };
                capitalPriceTrackings.Add(newCapitalPriceTrackingDto);
            }
            else
            {
                capitalPriceTrackings[startedIndex].Amount = newAmount;

                for (int i = startedIndex; i < capitalPriceTrackings.Count; i++)
                {
                    if (capitalPriceTrackings[i].BillId != Guid.Empty) // this is a bill. we need to decrease the invetory
                    {
                        capitalPriceTrackings[i].Inventory = capitalPriceTrackings[i - 1].Inventory - capitalPriceTrackings[i].Amount;
                    }
                    else
                    {
                        capitalPriceTrackings[i].Inventory = capitalPriceTrackings[i - 1].Inventory + capitalPriceTrackings[i].Amount;
                    }

                    if (capitalPriceTrackings[i].BillId == Guid.Empty) // this is not a bill. we only update capital price for warehousing and inventory
                    {
                        capitalPriceTrackings[i].CapitalPrice =
                            ProductStorageHelper.CalculateCapitalPrice(
                                capitalPriceTrackings[i - 1].Inventory,
                                capitalPriceTrackings[i - 1].CapitalPrice,
                                capitalPriceTrackings[i].Amount,
                                capitalPriceTrackings[i].InputPrice
                                );
                    }
                    else
                    {
                        capitalPriceTrackings[i].CapitalPrice = capitalPriceTrackings[i - 1].CapitalPrice;
                    }
                }
            }

            productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);
            productStorage.CapitalPrice          = capitalPriceTrackings[capitalPriceTrackings.Count - 1].CapitalPrice;
            productStorage.Inventory             = capitalPriceTrackings[capitalPriceTrackings.Count - 1].Inventory;
            _context.ProductStorages.Update(productStorage);
        }
        public async Task <IActionResult> ChangeInitialCapitalPriceTracking(Guid id, [FromBody] CapitalPriceTrackingDto updationDto)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(new ApiError(ModelState)));
            }

            try
            {
                var capitalPriceTrackingDetails = await _productStorageRepository.ChangeInitialCapitalPriceTracking(id, updationDto);

                return(Ok(new { CapitalPriceTrackingDetails = capitalPriceTrackingDetails }));
            }
            catch (Exception ex)
            {
                return(BadRequest(new ExceptionResponse(ex.Message)));
            }
        }
 private string _getTrackingType(CapitalPriceTrackingDto capitalPriceTracking)
 {
     if (capitalPriceTracking.BillId == Guid.Empty && capitalPriceTracking.WarehousingId == Guid.Empty && capitalPriceTracking.InventoryId == Guid.Empty)
     {
         return("inital_creating");
     }
     else if (capitalPriceTracking.BillId != Guid.Empty)
     {
         return("bill");
     }
     else if (capitalPriceTracking.WarehousingId != Guid.Empty)
     {
         return("warehousing");
     }
     else if (capitalPriceTracking.InventoryId != Guid.Empty)
     {
         return("inventory");
     }
     return("");
 }
        private async Task <string> _getCode(CapitalPriceTrackingDto capitalPriceTracking)
        {
            if (capitalPriceTracking.BillId != Guid.Empty)
            {
                var bill = await _context.Bills.SingleOrDefaultAsync(b => b.Id == capitalPriceTracking.BillId);

                return(bill.Code);
            }
            if (capitalPriceTracking.WarehousingId != Guid.Empty)
            {
                var warehousing = await _context.Warehousings.SingleOrDefaultAsync(w => w.Id == capitalPriceTracking.WarehousingId);

                return(warehousing.Code);
            }
            if (capitalPriceTracking.InventoryId != Guid.Empty)
            {
                var inventory = await _context.Inventories.SingleOrDefaultAsync(i => i.Id == capitalPriceTracking.InventoryId);

                return(inventory.Code);
            }

            return("");
        }
        public async Task <List <CapitalPriceTrackingDetailDto> > ChangeInitialCapitalPriceTracking(Guid productStorageId, CapitalPriceTrackingDto updatedDto)
        {
            var productStorage = await _entity.SingleOrDefaultAsync(ps => ps.Id == productStorageId);

            if (productStorage == null)
            {
                throw new Exception("Can not find product storage with id=" + productStorageId);
            }
            var capitalPriceTrackings = (productStorage.CapitalPriceTrackings == null) ?
                                        new List <CapitalPriceTrackingDto>() : JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);

            if (capitalPriceTrackings.Count > 0)
            {
                if (_isDefaultRecord(capitalPriceTrackings[0]))
                {
                    capitalPriceTrackings = ProductStorageHelper.UpdateCapitalPriceTracking(0, updatedDto, capitalPriceTrackings);
                    productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);
                    productStorage.Inventory             = capitalPriceTrackings[capitalPriceTrackings.Count - 1].Inventory;
                    productStorage.CapitalPrice          = capitalPriceTrackings[capitalPriceTrackings.Count - 1].CapitalPrice;
                    _entity.Update(productStorage);
                    await _context.SaveChangesAsync();

                    List <CapitalPriceTrackingDetailDto> capitalPriceTrackingDetails = await GetCapitalPriceHistory(productStorageId);

                    return(capitalPriceTrackingDetails);
                }
                else
                {
                    throw new Exception("This is not default record");
                }
            }
            return(null);
        }
 private bool _isDefaultRecord(CapitalPriceTrackingDto capitalPriceTrackingDto)
 {
     return(capitalPriceTrackingDto.BillId == Guid.Empty && capitalPriceTrackingDto.WarehousingId == Guid.Empty && capitalPriceTrackingDto.InventoryId == Guid.Empty);
 }
        public async Task <bool> FixAllCapitalPriceTracking()
        {
            bool finished = false;

            var bills = await _context.Bills.Where(b => b.IsActive == true).ToListAsync();

            foreach (var bill in bills)
            {
                var productList = JsonConvert.DeserializeObject <List <ProductForBillCreationDto> >(bill.ProductList);
                foreach (var product in productList)
                {
                    var productStorage = await _context.ProductStorages.SingleOrDefaultAsync(ps => ps.ProductId == product.Id && ps.StorageId == bill.StorageId);

                    var capitalPriceTrackings = (productStorage.CapitalPriceTrackings == null) ?
                                                new List <CapitalPriceTrackingDto>() : JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);

                    CapitalPriceTrackingDto defaultRecord = new CapitalPriceTrackingDto();

                    if (capitalPriceTrackings.Count == 0)
                    {
                        capitalPriceTrackings.Add(defaultRecord);
                    }
                    else if (capitalPriceTrackings[0].WarehousingId != Guid.Empty && capitalPriceTrackings[0].BillId != Guid.Empty)
                    {
                        capitalPriceTrackings.Add(defaultRecord);
                    }

                    var existed = capitalPriceTrackings.Find(c => c.BillId == bill.Id);
                    if (existed == null)
                    {
                        capitalPriceTrackings.Add(new CapitalPriceTrackingDto {
                            BillId       = bill.Id,
                            InputPrice   = 0,
                            Amount       = product.Amount,
                            CapitalPrice = capitalPriceTrackings[capitalPriceTrackings.Count - 1].CapitalPrice,
                            Inventory    = capitalPriceTrackings[capitalPriceTrackings.Count - 1].Inventory + product.Amount
                        });
                    }
                    productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);
                    _context.ProductStorages.Update(productStorage);
                }
            }
            ;
            await _context.SaveChangesAsync();

            var warehousings = await _context.Warehousings.Where(b => b.IsActive == true).ToListAsync();

            foreach (var warehousing in warehousings)
            {
                var productList = JsonConvert.DeserializeObject <List <ProductForWareshousingCreationDto> >(warehousing.ProductList);
                foreach (var product in productList)
                {
                    var productStorage = await _context.ProductStorages.SingleOrDefaultAsync(ps => ps.ProductId == product.Id && ps.StorageId == warehousing.StorageId);

                    var capitalPriceTrackings = (productStorage.CapitalPriceTrackings == null) ?
                                                new List <CapitalPriceTrackingDto>() : JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);

                    CapitalPriceTrackingDto defaultRecord = new CapitalPriceTrackingDto();

                    if (capitalPriceTrackings.Count == 0)
                    {
                        capitalPriceTrackings.Add(defaultRecord);
                    }
                    else if (capitalPriceTrackings[0].WarehousingId != Guid.Empty && capitalPriceTrackings[0].BillId != Guid.Empty)
                    {
                        capitalPriceTrackings.Add(defaultRecord);
                    }

                    var existed = capitalPriceTrackings.Find(c => c.WarehousingId == warehousing.Id);
                    if (existed == null)
                    {
                        var lastestRecord = capitalPriceTrackings[capitalPriceTrackings.Count - 1];
                        capitalPriceTrackings.Add(new CapitalPriceTrackingDto
                        {
                            BillId       = warehousing.Id,
                            InputPrice   = product.InputPrice,
                            Amount       = product.InputAmount,
                            CapitalPrice = ProductStorageHelper.CalculateCapitalPrice(lastestRecord.Inventory, lastestRecord.CapitalPrice, product.InputAmount, product.InputPrice),
                            Inventory    = lastestRecord.Inventory + product.InputAmount
                        });
                    }
                    productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);
                    _context.ProductStorages.Update(productStorage);
                }
            }
            ;
            await _context.SaveChangesAsync();

            var productStorages = await _context.ProductStorages.ToListAsync();

            foreach (var productStorage in productStorages)
            {
                var capitalPriceTrackings = (productStorage.CapitalPriceTrackings == null) ?
                                            new List <CapitalPriceTrackingDto>() : JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);

                CapitalPriceTrackingDto defaultRecord = new CapitalPriceTrackingDto();

                if (capitalPriceTrackings.Count == 0 || !_isDefaultRecord(capitalPriceTrackings[0]))
                {
                    capitalPriceTrackings.Insert(0, defaultRecord);
                }



                List <int> removeIndexs = new List <int>();

                for (int i = 1; i < capitalPriceTrackings.Count; i++)
                {
                    if (_isDefaultRecord(capitalPriceTrackings[i]))
                    {
                        removeIndexs.Add(i);
                    }
                    else if (capitalPriceTrackings[i].BillId != Guid.Empty)
                    {
                        capitalPriceTrackings[i].InputPrice   = 0;
                        capitalPriceTrackings[i].CapitalPrice = capitalPriceTrackings[i - 1].CapitalPrice;
                        capitalPriceTrackings[i].Inventory    = capitalPriceTrackings[i - 1].Inventory - capitalPriceTrackings[i].Amount;
                    }
                    else if (capitalPriceTrackings[i].WarehousingId != Guid.Empty)
                    {
                        capitalPriceTrackings[i].CapitalPrice = ProductStorageHelper
                                                                .CalculateCapitalPrice(
                            capitalPriceTrackings[i - 1].Inventory,
                            capitalPriceTrackings[i - 1].CapitalPrice,
                            capitalPriceTrackings[i].Amount,
                            capitalPriceTrackings[i].InputPrice);

                        capitalPriceTrackings[i].Inventory = capitalPriceTrackings[i - 1].Inventory
                                                             + capitalPriceTrackings[i].Amount;
                    }
                }
                foreach (int index in removeIndexs)
                {
                    capitalPriceTrackings.RemoveAt(index);
                }
                productStorage.Inventory             = capitalPriceTrackings[capitalPriceTrackings.Count - 1].Inventory;
                productStorage.CapitalPrice          = capitalPriceTrackings[capitalPriceTrackings.Count - 1].CapitalPrice;
                productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);
                _context.ProductStorages.Update(productStorage);
            }
            await _context.SaveChangesAsync();

            finished = true;

            return(finished);
        }
        new public async Task <Guid> EditAsync(Guid id, WarehousingForCreationDto updationDto)
        {
            var warehousing = await _entity.SingleOrDefaultAsync(w => w.Id == id);

            if (warehousing == null)
            {
                throw new Exception("Can not find warehousing with id = " + id);
            }
            if (!warehousing.IsActive)
            {
                throw new Exception("The destroyed warehousing can not be edited");
            }

            var oldProducts    = JsonConvert.DeserializeObject <List <ProductForWareshousingCreationDto> >(warehousing.ProductList);
            var editedProducts = updationDto.ProductList;

            double productMoney = 0;

            // when a old product is removed in new product list, we remove inventory
            foreach (var oldProduct in oldProducts)
            {
                var editedProduct = editedProducts.SingleOrDefault(p => p.Id == oldProduct.Id);
                if (editedProduct == null)
                {
                    await _removeCapitalTracking(oldProduct, updationDto.StorageId, id);
                }
            }

            foreach (var editedProduct in editedProducts)
            {
                // calculate product money
                productMoney += editedProduct.InputAmount * editedProduct.InputPrice;

                /* when not finding edited product on old product list, let add a new cappital tracking into
                 * ProductStorage of edited product */

                var oldProduct = oldProducts.SingleOrDefault(p => p.Id == editedProduct.Id);
                if (oldProduct == null)
                {
                    var productStorage = await _context.ProductStorages.SingleOrDefaultAsync(p => p.ProductId == editedProduct.Id &&
                                                                                             p.StorageId == warehousing.StorageId);

                    _addCapitalTracking(editedProduct, updationDto.StorageId, id, productStorage);
                }
                else
                {
                    var productStorage = await _context.ProductStorages.SingleOrDefaultAsync(p => p.ProductId == editedProduct.Id &&
                                                                                             p.StorageId == warehousing.StorageId);

                    // if we find a old product is same with edited product, we need to to update ProductProductionDate
                    if (editedProduct.DetailInputAmountList != null && editedProduct.DetailInputAmountList.Count > 0)
                    {
                        _updateInventoryDetail(editedProduct, oldProduct, productStorage);
                    }

                    // if we find old product is same with edited product, we need to update capital tracking of product storage


                    var capitalPriceTrackings = JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);
                    int index = capitalPriceTrackings.FindIndex(c => c.WarehousingId == id);
                    if (index == -1) // hot fix, this shit. duplicate warehousing when create cause error on destroy, it remove all warehousing
                    {
                        var lastestRecord = capitalPriceTrackings[capitalPriceTrackings.Count - 1];

                        CapitalPriceTrackingDto capitalPriceTrackingDto = new CapitalPriceTrackingDto()
                        {
                            WarehousingId = id,
                            BillId        = Guid.Empty,
                            InventoryId   = Guid.Empty,
                            Amount        = editedProduct.InputAmount,
                            Inventory     = lastestRecord.Inventory + editedProduct.InputAmount,
                            CapitalPrice  = ProductStorageHelper.CalculateCapitalPrice(
                                lastestRecord.Inventory,
                                lastestRecord.CapitalPrice,
                                editedProduct.InputAmount,
                                editedProduct.InputPrice
                                )
                        };
                        capitalPriceTrackings.Add(capitalPriceTrackingDto);

                        index = capitalPriceTrackings.Count - 1;
                    }


                    double deltaInventory = editedProduct.InputAmount - oldProduct.InputAmount;

                    var result = ChangeCapitalPriceTrackingsResultHelper.ChangeCapitalPriceTrackings(index,
                                                                                                     deltaInventory, editedProduct.InputPrice, capitalPriceTrackings, false);

                    if (!setting.IsAllowNegativeInventoryBill && result.Inventory < 0)
                    {
                        throw new Exception("change_warehousing_make_negative_inventory");
                    }
                    // remove tracking record
                    capitalPriceTrackings.RemoveAt(index);
                    // save new information
                    productStorage.Inventory             = result.Inventory;
                    productStorage.CapitalPrice          = result.CapitalPrice;
                    productStorage.CapitalPriceTrackings = result.CapitalPriceTrackingsJson;

                    _context.Update(productStorage);
                }
            }

            foreach (PropertyInfo propertyInfo in updationDto.GetType().GetProperties())
            {
                if (warehousing.GetType().GetProperty(propertyInfo.Name) != null &&
                    propertyInfo.Name != "ProductList" &&
                    propertyInfo.Name != "SupplierBillList" &&
                    propertyInfo.Name != "InputDate"
                    )
                {
                    warehousing.GetType().GetProperty(propertyInfo.Name).SetValue(warehousing, propertyInfo.GetValue(updationDto, null));
                }
            }

            warehousing.SupplierBillList = JsonConvert.SerializeObject(updationDto.SupplierBillList);
            warehousing.UpdatedDateTime  = DateTime.Now;

            var user = await _userManager.GetUserAsync(_httpContextAccessor.HttpContext.User);

            warehousing.UpdatedUserId = user.Id;
            warehousing.ProductList   = JsonConvert.SerializeObject(updationDto.ProductList);


            warehousing.ProductMoney = productMoney;
            warehousing.SummaryMoney = warehousing.ProductMoney + warehousing.TaxMoney;
            warehousing.DebtMoney    = warehousing.SummaryMoney - updationDto.PaymentMoney;

            _entity.Update(warehousing);

            var created = await _context.SaveChangesAsync();

            if (created < 1)
            {
                throw new InvalidOperationException("Database context could not create Warehousing.");
            }

            return(warehousing.Id);
        }
Exemple #11
0
        new public async Task <Guid> CreateAsync(ProductForCreationDto creationDto)
        {
            var newProduct = new ProductEntity();

            var existedProduct = await _entity.SingleOrDefaultAsync(p => p.Code == creationDto.Code);

            if (existedProduct != null)
            {
                throw new InvalidOperationException("Product has Code which is existed on database");
            }

            foreach (PropertyInfo propertyInfo in creationDto.GetType().GetProperties())
            {
                if (newProduct.GetType().GetProperty(propertyInfo.Name) != null &&
                    propertyInfo.Name != "UnitConverterList")
                {
                    newProduct.GetType().GetProperty(propertyInfo.Name).SetValue(newProduct, propertyInfo.GetValue(creationDto, null));
                }
            }
            newProduct.UnitConverterList = (creationDto.UnitConverterList == null) ? null : JsonConvert.SerializeObject(creationDto.UnitConverterList);
            newProduct.UpdatePriceDate   = DateTime.Now;

            await _entity.AddAsync(newProduct);

            var storages = _context.Storages.ToArray();

            foreach (var storage in storages)
            {
                var productStorage = new ProductStorageEntity
                {
                    ProductId = newProduct.Id,
                    StorageId = storage.Id,
                    Inventory = 0
                };

                if (storage.Id == creationDto.CurrentStorageId)
                {
                    productStorage.Inventory     = creationDto.Inventory;
                    productStorage.PlacePosition = creationDto.PlacePosition;
                    productStorage.CapitalPrice  = creationDto.CapitalPrice;
                    if (creationDto.ProductProductionDateList != null)
                    {
                        foreach (var productProductionDate in creationDto.ProductProductionDateList)
                        {
                            if (productProductionDate.ProductionWeekYear != null)
                            {
                                DateTime productionDate = DateTimeHelper.ConvertWeekYearToDateTime(productProductionDate.ProductionWeekYear);
                                productProductionDate.ProductionDate = productionDate;
                            }
                        }
                        productStorage.ProductProductionDateList = JsonConvert.SerializeObject(creationDto.ProductProductionDateList);
                    }


                    // create tracking capital price
                    CapitalPriceTrackingDto capitalPriceTracking = new CapitalPriceTrackingDto
                    {
                        Amount       = creationDto.Inventory,
                        InputPrice   = creationDto.CapitalPrice,
                        CapitalPrice = creationDto.CapitalPrice,
                        Inventory    = creationDto.Inventory
                    };
                    var capitalPriceTrackings = new List <CapitalPriceTrackingDto>
                    {
                        capitalPriceTracking
                    };

                    productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);
                }
                await _context.ProductStorages.AddAsync(productStorage);
            }

            var created = await _context.SaveChangesAsync();

            if (created < 1)
            {
                throw new InvalidOperationException("Database context could not create data.");
            }
            return(newProduct.Id);
        }
        new public async Task <Guid> CreateAsync(BillForCreationDto creationDto)
        {
            var customer = await _customerEntity.FirstOrDefaultAsync(x => x.Id == creationDto.CustomerId);

            if (customer == null)
            {
                throw new Exception("Can not find any customer with this id");
            }

            if (creationDto.UsedPoints > customer.AccumulationPoint)
            {
                throw new Exception("UsedPoints must be less or equal AccumulationPoint");
            }

            var newBill = new BillEntity();

            foreach (PropertyInfo propertyInfo in creationDto.GetType().GetProperties())
            {
                if (newBill.GetType().GetProperty(propertyInfo.Name) != null && propertyInfo.Name != "ProductList")
                {
                    newBill.GetType().GetProperty(propertyInfo.Name).SetValue(newBill, propertyInfo.GetValue(creationDto, null));
                }
            }

            var settings       = _context.Settings.ToList();
            var defaultSetting = settings[0];

            // we have a lot of data to save!
            newBill.PointMoney      = defaultSetting.PointToMoney * creationDto.UsedPoints;
            newBill.PointEarning    = Math.Round(creationDto.TotalMoney / defaultSetting.MoneyToPoint, 1);
            newBill.CreatedDateTime = DateTimeHelper.GetVietnamNow();
            newBill.IsActive        = true;

            newBill.ProductList = JsonConvert.SerializeObject(creationDto.ProductList);

            var user = await _userManager.GetUserAsync(_httpContextAccessor.HttpContext.User);

            newBill.UserId = user.Id;

            // generate the code
            bool isDuplicated = false;

            do
            {
                string lastestCode = _entity.Max(w => w.Code);
                newBill.Code = CodeGeneratorHelper.GetGeneratedCode(CONSTANT.BILL_PREFIX, lastestCode, CONSTANT.GENERATED_NUMBER_LENGTH);
                isDuplicated = await _isDuplicatedCode(newBill.Code);
            } while (isDuplicated);


            await _entity.AddAsync(newBill);

            // update accumulation points
            customer.AccumulationPoint += newBill.PointEarning - creationDto.UsedPoints;
            customer.AccumulationPoint  = Math.Round(customer.AccumulationPoint, 1);
            if (creationDto.IsUpdatedCustomerShipping)
            {
                customer.ShipAddress     = newBill.ShipAddress;
                customer.ShipContactName = newBill.ShipContactName;
                customer.ShipPhone       = newBill.ShipPhone;
                customer.CompanyName     = newBill.CompanyName;
                customer.CompanyAddress  = newBill.CompanyAddress;
                customer.CompanyTaxCode  = newBill.CompanyTaxCode;
            }

            _customerEntity.Update(customer);

            // update inventory for eact saled product

            foreach (ProductForBillCreationDto product in creationDto.ProductList)
            {
                if (product.IsService) // if product is service, we need not update anymore
                {
                    continue;
                }
                var productStorage = _context.ProductStorages.FirstOrDefault(p => p.ProductId == product.Id && p.StorageId == creationDto.StorageId);
                // if has a ProductStorage, we update inventory number.
                if (productStorage != null)
                {
                    if (product.Amount > productStorage.Inventory && !defaultSetting.IsAllowNegativeInventoryBill)
                    {
                        throw new Exception("amount_overcomes_inventory");
                    }
                    productStorage.Inventory -= product.Amount;
                    // update detail output amount

                    _addOrUpdateProductProductionDate(productStorage, product, true);

                    CapitalPriceTrackingDto capitalPriceTracking = new CapitalPriceTrackingDto
                    {
                        BillId       = newBill.Id,
                        Amount       = product.Amount,
                        CapitalPrice = productStorage.CapitalPrice,
                        Inventory    = productStorage.Inventory
                    };
                    productStorage.CapitalPriceTrackings = productStorage.CapitalPriceTrackings ?? "[]";

                    var capitalPriceTrackings = JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);
                    capitalPriceTrackings.Add(capitalPriceTracking);
                    productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);

                    _context.ProductStorages.Update(productStorage);
                }
                else
                {
                    throw new Exception("ProductStorage is not exist");
                }
            }

            var created = await _context.SaveChangesAsync();

            if (created < 1)
            {
                throw new InvalidOperationException("Database context could not create data.");
            }
            return(newBill.Id);
        }
        public async Task <Guid> BalanceAsync(Guid id)
        {
            var inventory = await _entity.SingleOrDefaultAsync(r => r.Id == id);

            if (inventory == null)
            {
                throw new Exception("Can not find object with this Id.");
            }
            if (inventory.Status == CONSTANT.INVENTORY_DESTROY || inventory.Status == CONSTANT.INVENTORY_BANLANCED)
            {
                throw new Exception("Inventory has balanced or destroy status does not allow for balancing");
            }
            inventory.BalanceDateTime = DateTime.Now;

            var user = await _userManager.GetUserAsync(_httpContextAccessor.HttpContext.User);

            inventory.BalanceUserId = user.Id;

            ProductForBalanceInventoryDto[] products = JsonConvert.DeserializeObject <ProductForBalanceInventoryDto[]>(inventory.ProductList);

            foreach (var product in products)
            {
                var productStorage = await _context.ProductStorages.SingleOrDefaultAsync(p => p.StorageId == inventory.StorageId && p.ProductId == product.Id);

                if (productStorage == null)
                {
                    throw new Exception("Can not find productStorage with productId");
                }
                productStorage.Inventory = product.RealInventory;

                // we need to update CapitalPriceTrackings
                productStorage.CapitalPriceTrackings = productStorage.CapitalPriceTrackings ?? "[]";

                var capitalPriceTrackings       = JsonConvert.DeserializeObject <List <CapitalPriceTrackingDto> >(productStorage.CapitalPriceTrackings);
                var lastestCapitalPriceTracking = capitalPriceTrackings.Last();
                var newCapitalPriceTracking     = new CapitalPriceTrackingDto()
                {
                    InventoryId  = id,
                    Inventory    = product.RealInventory,
                    Amount       = 0,
                    CapitalPrice = lastestCapitalPriceTracking.CapitalPrice,
                    InputPrice   = 0
                };
                capitalPriceTrackings.Add(newCapitalPriceTracking);
                productStorage.CapitalPriceTrackings = JsonConvert.SerializeObject(capitalPriceTrackings);

                _context.ProductStorages.Update(productStorage);
            }

            inventory.Status = CONSTANT.INVENTORY_BANLANCED;
            _entity.Update(inventory);

            var updated = await _context.SaveChangesAsync();

            if (updated < 1)
            {
                throw new Exception("Context can not updated");
            }

            return(inventory.Id);
        }
        public static ChangeCapitalPriceTrackingsResult ChangeCapitalPriceTrackings(int startedIndex, double deltaInventory, double inputPrice, List <CapitalPriceTrackingDto> capitalPriceTrackings, bool isRemove)
        {
            if (startedIndex == 0) // missing default record, add one (this is a hot fix)
            {
                CapitalPriceTrackingDto capitalPriceTrackingDto = new CapitalPriceTrackingDto()
                {
                    BillId        = Guid.Empty,
                    WarehousingId = Guid.Empty,
                    InventoryId   = Guid.Empty,
                    InputPrice    = capitalPriceTrackings[0].InputPrice,
                    CapitalPrice  = capitalPriceTrackings[0].CapitalPrice,
                    Inventory     = capitalPriceTrackings[0].Inventory
                };
                capitalPriceTrackings.Insert(0, capitalPriceTrackingDto);
                startedIndex = 1;
            }
            if (isRemove)
            {
                capitalPriceTrackings.RemoveAt(startedIndex);
            }
            else
            {
                capitalPriceTrackings[startedIndex].Amount    += deltaInventory;
                capitalPriceTrackings[startedIndex].InputPrice = inputPrice;
            }

            for (int i = startedIndex; i < capitalPriceTrackings.Count; i++)
            {
                int previousIndex = (i - 1 < 0) ? 0 : (i - 1);                            // this is a hot shit for fix bug: do not create default capital price tracking when create a product on other storage
                if (previousIndex == 0)                                                   // shit here
                {
                    capitalPriceTrackings[i].Inventory = capitalPriceTrackings[i].Amount; // shit here
                }
                else
                {
                    if (capitalPriceTrackings[i].WarehousingId != Guid.Empty) // warehousing record
                    {
                        capitalPriceTrackings[i].Inventory    = capitalPriceTrackings[previousIndex].Inventory + capitalPriceTrackings[i].Amount;
                        capitalPriceTrackings[i].CapitalPrice =

                            capitalPriceTrackings[i].CapitalPrice =
                                ProductStorageHelper.CalculateCapitalPrice(
                                    capitalPriceTrackings[previousIndex].Inventory,
                                    capitalPriceTrackings[previousIndex].CapitalPrice,
                                    capitalPriceTrackings[i].Amount,
                                    capitalPriceTrackings[i].InputPrice
                                    );
                    }
                    else if (capitalPriceTrackings[i].BillId != Guid.Empty)// Bill record record
                    {
                        capitalPriceTrackings[i].Inventory    = capitalPriceTrackings[previousIndex].Inventory - capitalPriceTrackings[i].Amount;
                        capitalPriceTrackings[i].CapitalPrice = capitalPriceTrackings[previousIndex].CapitalPrice;
                    }
                }
            }
            var inventory    = capitalPriceTrackings[capitalPriceTrackings.Count - 1].Inventory;
            var capitalPrice = capitalPriceTrackings[capitalPriceTrackings.Count - 1].CapitalPrice;
            var capitalPriceTrackingsJson = JsonConvert.SerializeObject(capitalPriceTrackings);

            return(new ChangeCapitalPriceTrackingsResult
            {
                Inventory = inventory,
                CapitalPrice = capitalPrice,
                CapitalPriceTrackingsJson = capitalPriceTrackingsJson
            });
        }