Skip to content
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ task generateTsClient(type: org.openapitools.generator.gradle.plugin.tasks.Gener
]
}
task publishJavaClientToMavenLocal(type: Exec, dependsOn: generateJavaClient) {
if (Os.isFamily(Os.FAMILY_WINDOWS)){
commandLine './.shell/publish_gen_to_maven_local.bat'
} else {
commandLine './.shell/publish_gen_to_maven_local.sh'
}
if (Os.isFamily(Os.FAMILY_WINDOWS)){
commandLine './.shell/publish_gen_to_maven_local.bat'
} else {
commandLine './.shell/publish_gen_to_maven_local.sh'
}
}
tasks.compileJava.dependsOn publishJavaClientToMavenLocal

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package school.hei.haapi.endpoint.rest.controller;

import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import school.hei.haapi.endpoint.rest.mapper.CreditMapper;
import school.hei.haapi.endpoint.rest.model.Credit;
import school.hei.haapi.endpoint.rest.model.CreditTransaction;
import school.hei.haapi.model.BoundedPageSize;
import school.hei.haapi.model.PageFromOne;
import school.hei.haapi.model.TrackActivity;
import school.hei.haapi.model.exception.NotFoundException;
import school.hei.haapi.service.CreditService;

@RestController
@AllArgsConstructor
@TrackActivity
public class CreditController {
private final CreditService creditService;
private final CreditMapper creditMapper;

@GetMapping("/students/{student_id}/credit")
public Credit getCreditByStudentId(@PathVariable("student_id") String studentId) {
return creditService
.getCreditByStudentId(studentId)
.map(creditMapper::toRest)
.orElseThrow(
() ->
new NotFoundException(
"Student with id {" + studentId + "} doesn't have a credit yet."));
}

@GetMapping("/students/{student_id}/credit/transactions")
public List<CreditTransaction> getCreditTransactionsByStudentId(
@PathVariable("student_id") String studentId,
@RequestParam(value = "page", defaultValue = "1") PageFromOne page,
@RequestParam(value = "page_size", defaultValue = "10") BoundedPageSize pageSize) {
return creditMapper.toCreditTransactionRest(
creditService.getCreditTransactionsByStudentId(studentId, page, pageSize));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
Expand All @@ -22,7 +23,20 @@
import org.springframework.web.bind.annotation.RestController;
import school.hei.haapi.endpoint.rest.mapper.FeeMapper;
import school.hei.haapi.endpoint.rest.mapper.FeeTemplateMapper;
import school.hei.haapi.endpoint.rest.model.*;
import school.hei.haapi.endpoint.rest.model.AdvancedFeeStatisticsGeneration;
import school.hei.haapi.endpoint.rest.model.AdvancedFeeStatisticsType;
import school.hei.haapi.endpoint.rest.model.AdvancedFeesStatistics;
import school.hei.haapi.endpoint.rest.model.CreateFee;
import school.hei.haapi.endpoint.rest.model.CrupdateFeeTemplate;
import school.hei.haapi.endpoint.rest.model.CrupdateStudentFee;
import school.hei.haapi.endpoint.rest.model.Fee;
import school.hei.haapi.endpoint.rest.model.FeeCategory;
import school.hei.haapi.endpoint.rest.model.FeeStatusEnum;
import school.hei.haapi.endpoint.rest.model.FeeTemplate;
import school.hei.haapi.endpoint.rest.model.FeeTypeEnum;
import school.hei.haapi.endpoint.rest.model.FeesStatistics;
import school.hei.haapi.endpoint.rest.model.FeesWithStats;
import school.hei.haapi.endpoint.rest.model.MpbsStatus;
import school.hei.haapi.model.BoundedPageSize;
import school.hei.haapi.model.PageFromOne;
import school.hei.haapi.model.TrackActivity;
Expand Down Expand Up @@ -83,9 +97,13 @@ public List<Fee> updateStudentFees(@PathVariable String studentId, @RequestBody
var student = userService.getById(studentId);
List<school.hei.haapi.model.Fee> domainFeeList =
fees.stream().map(fee -> feeMapper.toDomain(fee, student)).collect(toList());
return feeService.updateAll(domainFeeList, studentId).stream()
.map(feeMapper::toRestFee)
.toList();
return feeService.updateAll(domainFeeList).stream().map(feeMapper::toRestFee).toList();
}

@PatchMapping("/students/{studentId}/fees/{feeId}")
public Fee archiveStudentFeeById(@PathVariable String studentId, @PathVariable String feeId) {
var fee = feeService.getById(feeId);
return feeMapper.toRestFee(feeService.archiveFee(fee));
}

@GetMapping("/students/{studentId}/fees")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package school.hei.haapi.endpoint.rest.controller;

import static java.util.stream.Collectors.toUnmodifiableList;
import static school.hei.haapi.model.PaymentStatus.VALIDATE;

import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -14,17 +16,16 @@
import school.hei.haapi.endpoint.rest.mapper.PaymentMapper;
import school.hei.haapi.endpoint.rest.model.CreatePayment;
import school.hei.haapi.endpoint.rest.model.Payment;
import school.hei.haapi.endpoint.rest.model.PaymentStatus;
import school.hei.haapi.model.BoundedPageSize;
import school.hei.haapi.model.PageFromOne;
import school.hei.haapi.service.FeeService;
import school.hei.haapi.service.PaymentService;

@RestController
@AllArgsConstructor
public class PaymentController {
private final PaymentService paymentService;
private final PaymentMapper paymentMapper;
private final FeeService feeService;

@PostMapping("/students/{studentId}/fees/{feeId}/payments")
public List<Payment> createPayments(
Expand All @@ -36,6 +37,13 @@ public List<Payment> createPayments(
.collect(toUnmodifiableList());
}

@PatchMapping("/students/payments/validate")
public List<Payment> validatePayments(@RequestBody List<String> paymentIds) {
var payments = paymentService.getByIds(paymentIds);
payments.forEach(payment -> payment.setStatus(VALIDATE));
return paymentMapper.toRestPayment(paymentService.saveAll(payments));
}

@DeleteMapping("/students/{studentId}/fees/{feeId}/payments/{paymentId}")
public Payment deleteStudentFeePaymentById(
@PathVariable(name = "studentId") String studentId,
Expand All @@ -54,4 +62,14 @@ public List<Payment> getPaymentsByStudentId(
.map(paymentMapper::toRestPayment)
.collect(toUnmodifiableList());
}

@GetMapping("/students/credit-payments")
public List<Payment> getCreditPaymentsByStatus(
@RequestParam(value = "status", required = false) PaymentStatus status,
@RequestParam(value = "page", required = false) PageFromOne page,
@RequestParam(value = "page_size", required = false) BoundedPageSize pageSize) {
return paymentMapper.toRestPayment(
paymentService.getCreditPaymentsByStatus(
school.hei.haapi.model.PaymentStatus.valueOf(String.valueOf(status)), page, pageSize));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package school.hei.haapi.endpoint.rest.mapper;

import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import school.hei.haapi.endpoint.rest.model.Credit;
import school.hei.haapi.endpoint.rest.model.CreditMovement;
import school.hei.haapi.endpoint.rest.model.CreditTransaction;
import school.hei.haapi.model.exception.NotFoundException;

@Component
@AllArgsConstructor
public class CreditMapper {
private final UserMapper userMapper;
private final FeeMapper feeMapper;

public Credit toRest(school.hei.haapi.model.Credit credit) {
if (credit == null) {
throw new NotFoundException("Student doesn't have credit yet.");
}
return new Credit()
.student(userMapper.toIdentifier(credit.getStudent()))
.amount(credit.getAmount());
}

public CreditTransaction toRest(school.hei.haapi.model.CreditTransaction creditTransaction) {
return new CreditTransaction()
.transactionId(creditTransaction.getId())
.amount(creditTransaction.getAmount())
.fee(feeMapper.toRestFee(creditTransaction.getFee()))
.credit(toRest(creditTransaction.getCredit()))
.movement(CreditMovement.valueOf(creditTransaction.getCreditMovement().toString()));
}

public List<CreditTransaction> toCreditTransactionRest(
List<school.hei.haapi.model.CreditTransaction> creditTransactions) {
return creditTransactions.stream().map(this::toRest).toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package school.hei.haapi.endpoint.rest.mapper;

import static java.lang.Boolean.TRUE;
import static school.hei.haapi.endpoint.rest.mapper.FileInfoMapper.ONE_DAY_DURATION_AS_LONG;
import static school.hei.haapi.endpoint.rest.model.FeeStatusEnum.LATE;
import static school.hei.haapi.endpoint.rest.model.FeeStatusEnum.PAID;
Expand All @@ -9,7 +10,12 @@
import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import school.hei.haapi.endpoint.rest.model.*;
import school.hei.haapi.endpoint.rest.model.CreateFee;
import school.hei.haapi.endpoint.rest.model.CrupdateStudentFee;
import school.hei.haapi.endpoint.rest.model.Fee;
import school.hei.haapi.endpoint.rest.model.FeeLetter;
import school.hei.haapi.endpoint.rest.model.FeeStatusEnum;
import school.hei.haapi.endpoint.rest.model.Mpbs;
import school.hei.haapi.endpoint.rest.validator.CreateFeeValidator;
import school.hei.haapi.model.User;
import school.hei.haapi.model.exception.BadRequestException;
Expand Down Expand Up @@ -54,6 +60,7 @@ public Fee toRestFee(school.hei.haapi.model.Fee fee) {
.updatedAt(fee.getUpdatedAt())
.dueDatetime(fee.getDueDatetime())
.studentFirstName(fee.getStudent().getFirstName())
.isArchived(fee.isArchived())
.letter(letter == null ? null : toLetterFee(letter));
}

Expand Down Expand Up @@ -87,6 +94,7 @@ public school.hei.haapi.model.Fee toDomain(Fee fee, User student) {
.comment(fee.getComment())
.creationDatetime(fee.getCreationDatetime())
.dueDatetime(fee.getDueDatetime())
.isArchived(TRUE.equals(fee.getIsArchived()))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import school.hei.haapi.endpoint.rest.model.Payment;
import school.hei.haapi.endpoint.rest.validator.CreatePaymentValidator;
import school.hei.haapi.model.Fee;
import school.hei.haapi.model.PaymentStatus;
import school.hei.haapi.model.exception.BadRequestException;
import school.hei.haapi.model.exception.NotFoundException;
import school.hei.haapi.service.FeeService;
Expand All @@ -26,9 +27,16 @@ public Payment toRestPayment(school.hei.haapi.model.Payment payment) {
.type(payment.getType())
.amount(payment.getAmount())
.comment(payment.getComment())
.status(
school.hei.haapi.endpoint.rest.model.PaymentStatus.valueOf(
payment.getStatus().toString()))
.creationDatetime(payment.getCreationDatetime());
}

public List<Payment> toRestPayment(List<school.hei.haapi.model.Payment> payments) {
return payments.stream().map(this::toRestPayment).toList();
}

private school.hei.haapi.model.Payment toDomainPayment(
Fee associatedFee, CreatePayment createPayment) {
createPaymentValidator.accept(createPayment);
Expand All @@ -38,6 +46,7 @@ private school.hei.haapi.model.Payment toDomainPayment(
.creationDatetime(createPayment.getCreationDatetime())
.amount(createPayment.getAmount())
.comment(createPayment.getComment())
.status(PaymentStatus.valueOf(createPayment.getStatus().toString()))
.build();
}

Expand All @@ -64,6 +73,8 @@ private Payment.TypeEnum toDomainPaymentType(CreatePayment.TypeEnum createPaymen
return Payment.TypeEnum.FIX;
case BANK_TRANSFER:
return Payment.TypeEnum.BANK_TRANSFER;
case CREDIT:
return Payment.TypeEnum.CREDIT;
default:
throw new BadRequestException("Unexpected paymentType: " + createPaymentType.getValue());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,14 @@ req, res, null, forbiddenWithRemoteInfo(req))))
antMatcher(GET, "/students/*/fees/*"),
antMatcher(GET, "/students/*/fees/*/payments/*/receipt/raw"),
antMatcher(DELETE, "/students/*/fees/*"),
antMatcher(PATCH, "/students/*/fees/*"),
antMatcher(GET, "/students/*/fees/*/payments"),
antMatcher(POST, "/students/*/fees/*/payments"),
antMatcher(DELETE, "/students/*/fees/*/payments/*"),
antMatcher(PATCH, "/students/payments/validate"),
antMatcher(GET, "/students/credit-payments"),
antMatcher(GET, "/students/{student_id}/credit"),
antMatcher(GET, "/students/{student_id}/credit/transactions"),
antMatcher(GET, "/students/*/fees"),
antMatcher(POST, "/students/*/fees"),
antMatcher(PUT, "/students/*/fees"),
Expand Down Expand Up @@ -572,6 +577,8 @@ req, res, null, forbiddenWithRemoteInfo(req))))
.hasRole(MONITOR.getRole())
.requestMatchers(DELETE, "/students/*/fees/*")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(PATCH, "/students/*/fees/*")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(GET, "/students/*/fees/*")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(
Expand Down Expand Up @@ -628,7 +635,7 @@ req, res, null, forbiddenWithRemoteInfo(req))))
.requestMatchers(GET, "/students/*/fees/*/payments")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(POST, "/students/*/fees/*/payments")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole(), STUDENT.getRole())
.requestMatchers(GET, "/students/*/fees")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(new SelfMatcher(POST, "/students/*/fees", "students"))
Expand All @@ -647,6 +654,14 @@ req, res, null, forbiddenWithRemoteInfo(req))))
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(POST, "/students/*/fees/*/payments")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(PATCH, "/students/payments/validate")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(GET, "/students/credit-payments")
.hasAnyRole(MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(GET, "/students/{student_id}/credit")
.hasAnyRole(STUDENT.getRole(), MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(GET, "/students/{student_id}/credit/transactions")
.hasAnyRole(STUDENT.getRole(), MANAGER.getRole(), ADMIN.getRole())
.requestMatchers(
new StudentMonitorMatcher(
GET, "/students/*", "students", monitoringStudentService))
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/school/hei/haapi/model/Credit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package school.hei.haapi.model;

import static jakarta.persistence.GenerationType.IDENTITY;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import java.io.Serializable;
import java.time.Instant;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@AllArgsConstructor
@Data
@NoArgsConstructor
@Builder
public class Credit implements Serializable {

@Id
@GeneratedValue(strategy = IDENTITY)
private String id;

@OneToOne
@JoinColumn(name = "student_id", nullable = false, updatable = false)
private User student;

private int amount;

private Instant creationDatetime;

@OneToMany(mappedBy = "credit", fetch = FetchType.LAZY)
private List<CreditTransaction> transactions;
}
6 changes: 6 additions & 0 deletions src/main/java/school/hei/haapi/model/CreditMovement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package school.hei.haapi.model;

public enum CreditMovement {
WITHDRAWAL,
DEPOSIT
}
Loading
Loading