/// <summary>
        /// Creates a model view with a material finish price information
        /// </summary>
        /// <param name="materialFinishPriceTableEntry">MaterialFinishPriceTableEntry with the material finish price</param>
        /// <returns>GetMaterialFinishPriceModelView with the material finish price information model view</returns>
        public static GetMaterialFinishPriceModelView fromMaterialFinishEntity(FinishPriceTableEntry materialFinishPriceTableEntry, string currency, string area)
        {
            GetMaterialFinishPriceModelView getMaterialFinishPriceModelView = new GetMaterialFinishPriceModelView();

            getMaterialFinishPriceModelView.finishId     = materialFinishPriceTableEntry.entity.Id;
            getMaterialFinishPriceModelView.id           = materialFinishPriceTableEntry.Id;
            getMaterialFinishPriceModelView.value        = materialFinishPriceTableEntry.price.value;
            getMaterialFinishPriceModelView.currency     = currency;
            getMaterialFinishPriceModelView.area         = area;
            getMaterialFinishPriceModelView.startingDate = LocalDateTimePattern.GeneralIso.Format(materialFinishPriceTableEntry.timePeriod.startingDate);
            getMaterialFinishPriceModelView.endingDate   = LocalDateTimePattern.GeneralIso.Format(materialFinishPriceTableEntry.timePeriod.endingDate);
            return(getMaterialFinishPriceModelView);
        }
        /// <summary>
        /// Updates a finish's price table entry
        /// </summary>
        /// <param name="modelView">model view containing updatable information</param>
        /// <returns>True if the update is successful</returns>
        public static GetMaterialFinishPriceModelView update(UpdateFinishPriceTableEntryModelView modelView, IHttpClientFactory clientFactory)
        {
            string             defaultCurrency    = CurrencyPerAreaConversionService.getBaseCurrency();
            string             defaultArea        = CurrencyPerAreaConversionService.getBaseArea();
            MaterialRepository materialRepository = PersistenceContext.repositories().createMaterialRepository();
            long materialId = modelView.entityId;

            bool performedAtLeastOneUpdate = false;

            Material material = materialRepository.find(materialId);

            if (material == null)
            {
                throw new ResourceNotFoundException(MATERIAL_NOT_FOUND);
            }

            foreach (Finish finish in material.Finishes)
            {
                if (finish.Id == modelView.finishId)
                {
                    FinishPriceTableRepository finishPriceTableRepository = PersistenceContext.repositories().createFinishPriceTableRepository();
                    long finishPriceTableEntryId = modelView.tableEntryId;

                    FinishPriceTableEntry tableEntryToUpdate = finishPriceTableRepository.find(finishPriceTableEntryId);

                    if (tableEntryToUpdate == null)
                    {
                        throw new ResourceNotFoundException(ENTRY_NOT_FOUND);
                    }

                    if (tableEntryToUpdate.entity.Id != modelView.finishId)
                    {
                        throw new InvalidOperationException(ENTRY_DOESNT_BELONG_TO_FINISH);
                    }

                    LocalDateTime currentTime = NodaTime.LocalDateTime.FromDateTime(SystemClock.Instance.GetCurrentInstant().ToDateTimeUtc());

                    if (modelView.priceTableEntry.startingDate != null && LocalDateTimePattern.GeneralIso.Format(tableEntryToUpdate.timePeriod.startingDate).Equals(modelView.priceTableEntry.startingDate))
                    {
                        if (tableEntryToUpdate.timePeriod.startingDate.CompareTo(currentTime) < 0)
                        {
                            throw new InvalidOperationException(PAST_DATE);
                        }
                    }

                    if (modelView.priceTableEntry.endingDate != null && LocalDateTimePattern.GeneralIso.Format(tableEntryToUpdate.timePeriod.endingDate).Equals(modelView.priceTableEntry.endingDate))
                    {
                        if (tableEntryToUpdate.timePeriod.endingDate.CompareTo(currentTime) < 0)
                        {
                            throw new InvalidOperationException(PAST_DATE);
                        }
                    }

                    if (modelView.priceTableEntry.price != null)
                    {
                        CurrenciesService.checkCurrencySupport(modelView.priceTableEntry.price.currency);
                        AreasService.checkAreaSupport(modelView.priceTableEntry.price.area);

                        Price newPrice = null;
                        try
                        {
                            if (defaultCurrency.Equals(modelView.priceTableEntry.price.currency) && defaultArea.Equals(modelView.priceTableEntry.price.area))
                            {
                                newPrice = Price.valueOf(modelView.priceTableEntry.price.value);
                            }
                            else
                            {
                                Task <double> convertedValueTask = new CurrencyPerAreaConversionService(clientFactory)
                                                                   .convertCurrencyPerAreaToDefaultCurrencyPerArea(
                                    modelView.priceTableEntry.price.currency,
                                    modelView.priceTableEntry.price.area,
                                    modelView.priceTableEntry.price.value);
                                convertedValueTask.Wait();
                                double convertedValue = convertedValueTask.Result;
                                newPrice = Price.valueOf(convertedValue);
                            }
                        }
                        catch (HttpRequestException)
                        {
                            newPrice = Price.valueOf(modelView.priceTableEntry.price.value);
                        }

                        tableEntryToUpdate.changePrice(newPrice);
                        performedAtLeastOneUpdate = true;
                    }

                    if (modelView.priceTableEntry.endingDate != null)
                    {
                        LocalDateTime newEndingDate;
                        try
                        {
                            string newEndingDateAsString = modelView.priceTableEntry.endingDate;
                            newEndingDate = LocalDateTimePattern.GeneralIso.Parse(newEndingDateAsString).GetValueOrThrow();
                            tableEntryToUpdate.changeTimePeriod(TimePeriod.valueOf(tableEntryToUpdate.timePeriod.startingDate, newEndingDate));
                            performedAtLeastOneUpdate = true;
                        }
                        catch (UnparsableValueException)
                        {
                            throw new UnparsableValueException(DATES_WRONG_FORMAT + LocalDateTimePattern.GeneralIso.PatternText);
                        }
                    }

                    if (modelView.priceTableEntry.startingDate != null)
                    {
                        LocalDateTime newStartingDate;
                        try
                        {
                            string newStartingDateAsString = modelView.priceTableEntry.startingDate;
                            newStartingDate = LocalDateTimePattern.GeneralIso.Parse(newStartingDateAsString).GetValueOrThrow();
                            tableEntryToUpdate.changeTimePeriod(TimePeriod.valueOf(newStartingDate, tableEntryToUpdate.timePeriod.endingDate));
                            performedAtLeastOneUpdate = true;
                        }
                        catch (UnparsableValueException)
                        {
                            throw new UnparsableValueException(DATES_WRONG_FORMAT + LocalDateTimePattern.GeneralIso.PatternText);
                        }
                    }

                    if (performedAtLeastOneUpdate)
                    {
                        FinishPriceTableEntry updatedTableEntry = finishPriceTableRepository.update(tableEntryToUpdate);

                        if (updatedTableEntry == null)
                        {
                            throw new InvalidOperationException(UPDATE_NOT_SUCCESSFUL);
                        }

                        GetMaterialFinishPriceModelView updatedTableEntryModelView = new GetMaterialFinishPriceModelView();

                        updatedTableEntryModelView.id           = updatedTableEntry.Id;
                        updatedTableEntryModelView.finishId     = updatedTableEntry.entity.Id;
                        updatedTableEntryModelView.value        = updatedTableEntry.price.value;
                        updatedTableEntryModelView.currency     = defaultCurrency;
                        updatedTableEntryModelView.area         = defaultArea;
                        updatedTableEntryModelView.startingDate = LocalDateTimePattern.GeneralIso.Format(updatedTableEntry.timePeriod.startingDate);
                        updatedTableEntryModelView.endingDate   = LocalDateTimePattern.GeneralIso.Format(updatedTableEntry.timePeriod.endingDate);

                        return(updatedTableEntryModelView);
                    }
                }
            }
            throw new ResourceNotFoundException(FINISH_NOT_FOUND_OR_DOESNT_BELONG_TO_MATERIAL);
        }
        /// <summary>
        /// Transforms and creates a finish price table entry
        /// </summary>
        /// <param name="modelView">model view with the necessary info to create a finish price table entry</param>
        /// <param name="clientFactory">injected client factory</param>
        /// <returns></returns>
        public static GetMaterialFinishPriceModelView create(AddFinishPriceTableEntryModelView modelView, IHttpClientFactory clientFactory)
        {
            string             defaultCurrency    = CurrencyPerAreaConversionService.getBaseCurrency();
            string             defaultArea        = CurrencyPerAreaConversionService.getBaseArea();
            MaterialRepository materialRepository = PersistenceContext.repositories().createMaterialRepository();
            long materialId = modelView.entityId;

            Material material = materialRepository.find(materialId);

            if (material == null)
            {
                throw new ResourceNotFoundException(MATERIAL_NOT_FOUND);
            }

            //TODO Is this null check enough? Should we check ,if an entry exists, that the time period of the price entry is valid?
            MaterialPriceTableEntry materialPriceTableEntry = PersistenceContext.repositories().createMaterialPriceTableRepository().find(materialId);

            if (materialPriceTableEntry == null)
            {
                throw new InvalidOperationException(MATERIAL_HAS_NO_PRICE);
            }

            foreach (Finish finish in material.Finishes)
            {
                if (finish.Id == modelView.finishId)
                {
                    string startingDateAsString = modelView.priceTableEntry.startingDate;
                    string endingDateAsString   = modelView.priceTableEntry.endingDate;

                    LocalDateTime startingDate;
                    LocalDateTime endingDate;
                    LocalDateTime currentTime = NodaTime.LocalDateTime.FromDateTime(SystemClock.Instance.GetCurrentInstant().ToDateTimeUtc());

                    try
                    {
                        startingDate = LocalDateTimePattern.GeneralIso.Parse(startingDateAsString).GetValueOrThrow();

                        if (startingDate.CompareTo(currentTime) < 0)
                        {
                            throw new InvalidOperationException(PAST_DATE);
                        }
                    }
                    catch (UnparsableValueException)
                    {
                        throw new UnparsableValueException(DATES_WRONG_FORMAT + LocalDateTimePattern.GeneralIso.PatternText);
                    }

                    TimePeriod timePeriod = null;

                    if (endingDateAsString != null)
                    {
                        try
                        {
                            endingDate = LocalDateTimePattern.GeneralIso.Parse(endingDateAsString).GetValueOrThrow();

                            if (endingDate.CompareTo(currentTime) < 0)
                            {
                                throw new InvalidOperationException(PAST_DATE);
                            }

                            timePeriod = TimePeriod.valueOf(startingDate, endingDate);
                        }
                        catch (UnparsableValueException)
                        {
                            throw new UnparsableValueException(DATES_WRONG_FORMAT + LocalDateTimePattern.GeneralIso.PatternText);
                        }
                    }
                    else
                    {
                        timePeriod = TimePeriod.valueOf(startingDate);
                    }

                    CurrenciesService.checkCurrencySupport(modelView.priceTableEntry.price.currency);
                    AreasService.checkAreaSupport(modelView.priceTableEntry.price.area);

                    Price price = null;
                    try
                    {
                        if (defaultCurrency.Equals(modelView.priceTableEntry.price.currency) && defaultArea.Equals(modelView.priceTableEntry.price.area))
                        {
                            price = Price.valueOf(modelView.priceTableEntry.price.value);
                        }
                        else
                        {
                            Task <double> convertedValueTask = new CurrencyPerAreaConversionService(clientFactory)
                                                               .convertCurrencyPerAreaToDefaultCurrencyPerArea(
                                modelView.priceTableEntry.price.currency,
                                modelView.priceTableEntry.price.area,
                                modelView.priceTableEntry.price.value);
                            convertedValueTask.Wait();
                            double convertedValue = convertedValueTask.Result;
                            price = Price.valueOf(convertedValue);
                        }
                    }
                    catch (HttpRequestException)
                    {
                        price = Price.valueOf(modelView.priceTableEntry.price.value);
                    }

                    FinishPriceTableEntry finishPriceTableEntry      = new FinishPriceTableEntry(material.id(), finish, price, timePeriod);
                    FinishPriceTableEntry savedFinishPriceTableEntry = PersistenceContext.repositories()
                                                                       .createFinishPriceTableRepository().save(finishPriceTableEntry);

                    if (savedFinishPriceTableEntry == null)
                    {
                        throw new InvalidOperationException(PRICE_TABLE_ENTRY_NOT_CREATED);
                    }

                    GetMaterialFinishPriceModelView createdPriceModelView = new GetMaterialFinishPriceModelView();

                    createdPriceModelView.startingDate = LocalDateTimePattern.GeneralIso.Format(savedFinishPriceTableEntry.timePeriod.startingDate);
                    createdPriceModelView.endingDate   = LocalDateTimePattern.GeneralIso.Format(savedFinishPriceTableEntry.timePeriod.endingDate);
                    createdPriceModelView.value        = savedFinishPriceTableEntry.price.value;
                    createdPriceModelView.currency     = defaultCurrency;
                    createdPriceModelView.area         = defaultArea;
                    createdPriceModelView.finishId     = finish.Id;
                    createdPriceModelView.id           = savedFinishPriceTableEntry.Id;

                    return(createdPriceModelView);
                }
            }
            throw new ResourceNotFoundException(FINISH_NOT_FOUND);
        }