class AbstractYourProjectCostsSaver extends AsyncAdaptor {

    public ServiceResult<Void> save(YourProjectCostsForm form, long targetId, OrganisationResource organisation, ValidationMessages messages) {
        BaseFinanceResource finance = getFinanceResource(targetId, organisation.getId());

        List<CompletableFuture<ValidationMessages>> futures = new ArrayList<>();

        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.LABOUR)) {
            futures.add(saveLabourCosts(form.getLabour(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.OVERHEADS)) {
            futures.add(saveOverheads(form.getOverhead(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.MATERIALS)) {
            futures.add(saveRows(form.getMaterialRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.CAPITAL_USAGE)) {
            futures.add(saveRows(form.getCapitalUsageRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.SUBCONTRACTING_COSTS)) {
            futures.add(saveRows(form.getSubcontractingRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.TRAVEL)) {
            futures.add(saveRows(form.getTravelRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.OTHER_COSTS)) {
            futures.add(saveRows(form.getOtherRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.PROCUREMENT_OVERHEADS)) {
            futures.add(saveRows(form.getProcurementOverheadRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.VAT)) {
            futures.add(saveVat(form.getVatForm(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.ASSOCIATE_SALARY_COSTS)) {
            futures.add(saveRowsAndDeleteBlank(form.getAssociateSalaryCostRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.ASSOCIATE_DEVELOPMENT_COSTS)) {
            futures.add(saveRowsAndDeleteBlank(form.getAssociateDevelopmentCostRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.ASSOCIATE_SUPPORT)) {
            futures.add(saveRows(form.getAssociateSupportCostRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.ESTATE_COSTS)) {
            futures.add(saveRows(form.getEstateCostRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.KNOWLEDGE_BASE)) {
            futures.add(saveRows(form.getKnowledgeBaseCostRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.CONSUMABLES)) {
            futures.add(saveRows(form.getConsumableCostRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.KTP_TRAVEL)) {
            futures.add(saveRows(form.getKtpTravelCostRows(), finance));
        }
        if (finance.getFinanceOrganisationDetails().containsKey(FinanceRowType.ADDITIONAL_COMPANY_COSTS)) {
            futures.add(saveAdditionalCompanyCosts(form.getAdditionalCompanyCostForm(), finance));
        }

        awaitAll(futures)
                .thenAccept(messages::addAll);

        if (messages.getErrors().isEmpty()) {
            return serviceSuccess();
        } else {
            return serviceFailure(messages.getErrors());
        }
    }

}