Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.arturjarosz.task.contractor.application;

import com.arturjarosz.task.dto.ContractorContractorJobsDataDto;
import com.arturjarosz.task.dto.ContractorDto;

import java.util.List;
Expand Down Expand Up @@ -34,4 +35,9 @@ public interface ContractorApplicationService {
*/
List<ContractorDto> getContractors();

/**
* Returns Contractor Jobs data for Contractor with given contractorId.
*/
ContractorContractorJobsDataDto getContractorJobsData(Long contractorId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import com.arturjarosz.task.contractor.application.ContractorApplicationService;
import com.arturjarosz.task.contractor.application.ContractorValidator;
import com.arturjarosz.task.contractor.application.mapper.ContractorContractorJobMapper;
import com.arturjarosz.task.contractor.application.mapper.ContractorMapper;
import com.arturjarosz.task.contractor.infrastructure.ContractorRepository;
import com.arturjarosz.task.contractor.model.ContractorCategory;
import com.arturjarosz.task.contractor.query.ContractorQueryService;
import com.arturjarosz.task.dto.ContractorContractorJobsDataDto;
import com.arturjarosz.task.dto.ContractorDto;
import com.arturjarosz.task.sharedkernel.annotations.ApplicationService;
import com.arturjarosz.task.sharedkernel.exceptions.ResourceNotFoundException;
Expand All @@ -24,6 +26,7 @@ public class ContractorApplicationServiceImpl implements ContractorApplicationSe
private final ContractorValidator contractorValidator;
private final ContractorMapper contractorMapper;
private final ContractorQueryService contractorQueryService;
private final ContractorContractorJobMapper contractorContractorJobMapper;


@Transactional
Expand Down Expand Up @@ -91,4 +94,14 @@ public List<ContractorDto> getContractors() {
numberOfJobsByContractorId.get(contractor.getId())))
.toList();
}

@Override
public ContractorContractorJobsDataDto getContractorJobsData(Long contractorId) {
LOG.debug("Loading Contractor Jobs data for Contractor with id {}", contractorId);

this.contractorValidator.validateContractorExistence(contractorId);
var data = this.contractorQueryService.getContractorJobsData(contractorId);

return this.contractorContractorJobMapper.mapToContractorContractorJobsDataDto(data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.arturjarosz.task.contractor.application.mapper;

import com.arturjarosz.task.configuration.UserProperties;
import com.arturjarosz.task.dto.ContractorContractorJobsDataDto;
import com.arturjarosz.task.dto.FinancialPartialDataDto;
import com.arturjarosz.task.finance.application.TaxCalculator;
import com.arturjarosz.task.finance.application.dto.FinancialValueDto;
import com.arturjarosz.task.finance.model.ContractorContractorJobDto;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Set;

@Mapper(uses = {UserProperties.class}, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public abstract class ContractorContractorJobMapper {

@Autowired
private UserProperties userProperties;

private static FinancialPartialDataDto calculateAverage(FinancialValueDto financialSummary, int count) {
var averageSummary = new FinancialPartialDataDto();
if (count > 0) {
averageSummary.setNetValue(financialSummary.getNetValue()
.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP)
.doubleValue());
averageSummary.setGrossValue(financialSummary.getGrossValue()
.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP)
.doubleValue());
averageSummary.setVatTax(financialSummary.getVatTax()
.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP)
.doubleValue());
averageSummary.setIncomeTax(financialSummary.getIncomeTax()
.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP)
.doubleValue());
} else {
averageSummary.setNetValue(0.0);
averageSummary.setGrossValue(0.0);
averageSummary.setIncomeTax(0.0);
averageSummary.setVatTax(0.0);
}
return averageSummary;
}

public ContractorContractorJobsDataDto mapToContractorContractorJobsDataDto(
Set<ContractorContractorJobDto> contractorContractorJobDtos) {
var contractorContractorJobsDataDto = new ContractorContractorJobsDataDto();

contractorContractorJobsDataDto.setContractorJobs(
contractorContractorJobDtos.stream().map(ContractorContractorJobDto::contractorJob).toList());

var financialSummary = new FinancialValueDto();
for (ContractorContractorJobDto contractorJobsDataDto : contractorContractorJobDtos) {
var contractorJobFinancialDetails = contractorJobsDataDto.financialData();
var recalculatedSupplyFinancialDetails = TaxCalculator.recalculateObjectTaxes(contractorJobFinancialDetails,
this.userProperties);
financialSummary.addValues(recalculatedSupplyFinancialDetails);
}
var financialSummaryDto = new FinancialPartialDataDto(contractorContractorJobDtos.size(),
financialSummary.getNetValue().doubleValue(), financialSummary.getGrossValue().doubleValue(),
financialSummary.getVatTax().doubleValue(), financialSummary.getIncomeTax().doubleValue());
financialSummaryDto.setCount(contractorContractorJobDtos.size());
contractorContractorJobsDataDto.setFinancialData(financialSummaryDto);

var averageSummary = calculateAverage(financialSummary, financialSummaryDto.getCount());
contractorContractorJobsDataDto.setAverageFinancialData(averageSummary);

return contractorContractorJobsDataDto;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.arturjarosz.task.contractor.query;

import com.arturjarosz.task.finance.model.ContractorContractorJobDto;

import java.util.Map;
import java.util.Set;

public interface ContractorQueryService {

Expand All @@ -10,4 +13,6 @@ public interface ContractorQueryService {
boolean contractorWithIdExists(long contractorId);

Map<Long, Long> getNumberOfJobsPerContractor();

Set<ContractorContractorJobDto> getContractorJobsData(long contractorId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,33 @@

import com.arturjarosz.task.contractor.model.QContractor;
import com.arturjarosz.task.contractor.query.ContractorQueryService;
import com.arturjarosz.task.finance.application.mapper.ContractorJobMapper;
import com.arturjarosz.task.finance.application.mapper.FinancialDataMapper;
import com.arturjarosz.task.finance.model.ContractorContractorJobDto;
import com.arturjarosz.task.finance.model.QContractorJob;
import com.arturjarosz.task.finance.model.QProjectFinancialData;
import com.arturjarosz.task.sharedkernel.annotations.Finder;
import com.arturjarosz.task.sharedkernel.infrastructure.AbstractQueryService;

import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Finder
public class ContractorQueryServiceImpl extends AbstractQueryService<QContractor> implements ContractorQueryService {

private static final QContractor CONTRACTOR = QContractor.contractor;
private static final QContractorJob CONTRACTOR_JOB = QContractorJob.contractorJob;
private static final QProjectFinancialData PROJECT_FINANCIAL_DATA = QProjectFinancialData.projectFinancialData;
private final ContractorJobMapper contractorJobMapper;
private final FinancialDataMapper financialDataMapper;

public ContractorQueryServiceImpl() {
public ContractorQueryServiceImpl(ContractorJobMapper contractorJobMapper,
FinancialDataMapper financialDataMapper) {
super(CONTRACTOR);
this.contractorJobMapper = contractorJobMapper;
this.financialDataMapper = financialDataMapper;
}

@Override
Expand All @@ -37,5 +49,24 @@ public Map<Long, Long> getNumberOfJobsPerContractor() {
.collect(Collectors.toMap(contractorIdToCount -> contractorIdToCount.get(CONTRACTOR.id),
contractorIdToCount -> contractorIdToCount.get(CONTRACTOR_JOB.count())));
}

@Override
public Set<ContractorContractorJobDto> getContractorJobsData(long contractorId) {
return this.query()
.from(CONTRACTOR_JOB)
.where(CONTRACTOR_JOB.contractorId.eq(contractorId))
.leftJoin(PROJECT_FINANCIAL_DATA)
.on(CONTRACTOR_JOB.projectFinancialDataId.eq(PROJECT_FINANCIAL_DATA.id))
.select(CONTRACTOR_JOB, PROJECT_FINANCIAL_DATA.projectId)
.fetch()
.stream()
.map(contractorJobAndProjectId -> new ContractorContractorJobDto(
this.contractorJobMapper.mapToDto(contractorJobAndProjectId.get(CONTRACTOR_JOB),
contractorJobAndProjectId.get(PROJECT_FINANCIAL_DATA.projectId)),
this.financialDataMapper.map(
Objects.requireNonNull(contractorJobAndProjectId.get(CONTRACTOR_JOB))
.getFinancialData())))
.collect(Collectors.toSet());
}
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.arturjarosz.task.contractor.rest;

import com.arturjarosz.task.contractor.application.ContractorApplicationService;
import com.arturjarosz.task.dto.ContractorContractorJobsDataDto;
import com.arturjarosz.task.dto.ContractorDto;
import com.arturjarosz.task.rest.ContractorApi;
import com.arturjarosz.task.sharedkernel.testhelpers.HttpHeadersBuilder;
Expand Down Expand Up @@ -31,22 +32,27 @@ public ResponseEntity<ContractorDto> createContractor(ContractorDto contractorDt
@Override
public ResponseEntity<ContractorDto> updateContractor(ContractorDto contractorDto, Long contractorId) {
var updatedContractor = this.contractorApplicationService.updateContractor(contractorId, contractorDto);
return new ResponseEntity<>(updatedContractor, HttpStatus.OK);
return ResponseEntity.ok(updatedContractor);
}

@Override
public ResponseEntity<Void> deleteContractor(Long contractorId) {
this.contractorApplicationService.deleteContractor(contractorId);
return new ResponseEntity<>(HttpStatus.OK);
return ResponseEntity.ok().build();
}

@Override
public ResponseEntity<ContractorDto> getContractor(Long contractorId) {
return new ResponseEntity<>(this.contractorApplicationService.getContractor(contractorId), HttpStatus.OK);
return ResponseEntity.ok(this.contractorApplicationService.getContractor(contractorId));
}

@Override
public ResponseEntity<List<ContractorDto>> getContractors() {
return new ResponseEntity<>(this.contractorApplicationService.getContractors(), HttpStatus.OK);
return ResponseEntity.ok(this.contractorApplicationService.getContractors());
}

@Override
public ResponseEntity<ContractorContractorJobsDataDto> getContractorJobsData(Long contractorId) {
return ResponseEntity.ok(this.contractorApplicationService.getContractorJobsData(contractorId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,4 @@ default ContractorJob mapFromDto(ContractorJobDto contractorJobDto) {
}

ContractorJobDto mapToDto(ContractorJob contractorJob, Long projectId);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.arturjarosz.task.finance.model;

import com.arturjarosz.task.dto.ContractorJobDto;
import com.arturjarosz.task.finance.domain.dto.FinancialDataDto;

public record ContractorContractorJobDto(ContractorJobDto contractorJob, FinancialDataDto financialData) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class ContractorJob extends AbstractHistoryAwareEntity implements Partial
@Column(name = "NAME", nullable = false)
String name;

@Getter
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "FINANCIAL_DATA_ID", referencedColumnName = "ID", nullable = false)
FinancialData financialData;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.arturjarosz.task.finance.application.mapper.FinancialDataMapper;
import com.arturjarosz.task.finance.application.mapper.SupplyMapper;
import com.arturjarosz.task.finance.model.QFinancialData;
import com.arturjarosz.task.finance.model.QProjectFinancialData;
import com.arturjarosz.task.finance.model.QSupply;
import com.arturjarosz.task.finance.model.SupplierSupplyDataDto;
Expand All @@ -19,7 +18,6 @@
public class SupplierQueryServiceImpl extends AbstractQueryService<QSupplier> implements SupplierQueryService {

private static final QProjectFinancialData PROJECT_FINANCIAL_DATA = QProjectFinancialData.projectFinancialData;
private static final QFinancialData FINANCIAL_DATA = QFinancialData.financialData;
private static final QSupplier SUPPLIER = QSupplier.supplier;
private static final QSupply SUPPLY = QSupply.supply;
private final SupplyMapper supplyMapper;
Expand Down
46 changes: 46 additions & 0 deletions core/src/main/resources/openapi/openapi-spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,36 @@ paths:
schema:
$ref: "#/components/schemas/ValidatorError"

/contractors/{contractorId}/contractor-jobs:
get:
tags:
- contractor
summary: Get all contractor jobs data for given contractor
operationId: getContractorJobsData
parameters:
- name: contractorId
in: path
description: "A unique identifier of the contractor"
required: true
style: simple
explode: false
schema:
type: integer
format: int64
responses:
200:
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/ContractorContractorJobsData"
400:
description: Validator error message
content:
application/json:
schema:
$ref: "#/components/schemas/ValidatorError"

/projects/{projectId}/contractor-jobs:
post:
tags:
Expand Down Expand Up @@ -2839,6 +2869,19 @@ components:
items:
$ref: "#/components/schemas/Contractor"

ContractorContractorJobsData:
type:
object
properties:
contractorJobs:
type: array
items:
$ref: "#/components/schemas/ContractorJob"
financialData:
$ref: "#/components/schemas/FinancialPartialData"
averageFinancialData:
$ref: "#/components/schemas/FinancialPartialData"

ContractorCategory:
type: string
enum:
Expand Down Expand Up @@ -2870,6 +2913,9 @@ components:
type: boolean
paid:
type: boolean
projectId:
type: integer
format: int64
createdDateTime:
type: string
format: time
Expand Down
Loading
Loading