Skip to content

Commit

Permalink
feat: students payments
Browse files Browse the repository at this point in the history
  • Loading branch information
hei-ryan committed Mar 17, 2022
1 parent 6a2be51 commit 88467cb
Show file tree
Hide file tree
Showing 12 changed files with 452 additions and 11 deletions.
54 changes: 47 additions & 7 deletions doc/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ paths:
required: true
schema:
type: string
operationId: getStudentPayments
operationId: getStudentFeePayments
responses:
'200':
description: List of all student payments
Expand Down Expand Up @@ -739,6 +739,15 @@ paths:
schema:
type: string
operationId: createStudentPayments
requestBody:
description: Student fees to create
required: true
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/CreatePayment'
responses:
'200':
description: Created student payments
Expand All @@ -747,7 +756,38 @@ paths:
schema:
type: array
items:
$ref: '#/components/schemas/CreatePayment'
$ref: '#/components/schemas/Payment'
'400':
$ref: '#/components/responses/400'
'403':
$ref: '#/components/responses/403'
'404':
$ref: '#/components/responses/404'
'429':
$ref: '#/components/responses/429'
'500':
$ref: '#/components/responses/500'
/students/{student_id}/fees/payments:
get:
tags:
- Paying
summary: Get all student payments
parameters:
- name: student_id
in: path
required: true
schema:
type: string
operationId: getStudentPayments
responses:
'200':
description: List of all student payments
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Payment'
'400':
$ref: '#/components/responses/400'
'403':
Expand All @@ -758,7 +798,6 @@ paths:
$ref: '#/components/responses/429'
'500':
$ref: '#/components/responses/500'

components:
securitySchemes:
BearerAuth:
Expand Down Expand Up @@ -943,6 +982,8 @@ components:
CreatePayment:
type: object
properties:
fee_id:
type: string
type:
type: string
enum:
Expand All @@ -953,17 +994,16 @@ components:
type: integer
comment:
type: string
creation_datetime:
type: string
format: date-time
Payment:
allOf:
- $ref: '#/components/schemas/CreatePayment'
type: object
properties:
id:
type: string

creation_datetime:
type: string
format: date-time
Page:
type: integer
description: Start at `1`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
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.service.PaymentService;

import static java.util.stream.Collectors.toUnmodifiableList;

@RestController
@AllArgsConstructor
public class PaymentController {

private final PaymentService paymentService;
private final PaymentMapper paymentMapper;

@PostMapping("/students/{studentId}/fees/{feeId}/payments")
public List<Payment> createPayments(
@PathVariable String studentId,
@PathVariable String feeId,
@RequestBody List<CreatePayment> toCreate) {
return paymentService
.saveAll(studentId, feeId, toCreate.stream()
.map(paymentMapper::toDomainPayment)
.collect(toUnmodifiableList()))
.stream()
.map(paymentMapper::toRestPayment)
.collect(toUnmodifiableList());
}

@GetMapping("/students/{studentId}/fees/{feeId}/payments")
public List<Payment> getFeePaymentsByStudentId(
@PathVariable String studentId, @PathVariable String feeId) {
return paymentService.getByStudentIdAndFeeId(studentId, feeId).stream()
.map(paymentMapper::toRestPayment)
.collect(toUnmodifiableList());
}

@GetMapping("/students/{studentId}/fees/payments")
public List<Payment> getPaymentsByStudentId(@PathVariable String studentId) {
return paymentService.getByStudentId(studentId).stream()
.map(paymentMapper::toRestPayment)
.collect(toUnmodifiableList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package school.hei.haapi.endpoint.rest.mapper;

import org.springframework.stereotype.Component;
import school.hei.haapi.endpoint.rest.model.CreatePayment;
import school.hei.haapi.endpoint.rest.model.Payment;
import school.hei.haapi.model.exception.BadRequestException;

@Component
public class PaymentMapper {
public Payment toRestPayment(school.hei.haapi.model.Payment payment) {
return new Payment()
.id(payment.getId())
.feeId(payment.getFeeId())
.type(payment.getType())
.amount(payment.getAmount())
.comment(payment.getComment())
.creationDatetime(payment.getCreationDatetime());
}

public school.hei.haapi.model.Payment toDomainPayment(CreatePayment createPayment) {
return school.hei.haapi.model.Payment.builder()
.feeId(createPayment.getFeeId())
.type(toDomainPaymentType(createPayment.getType()))
.amount(createPayment.getAmount())
.comment(createPayment.getComment())
.build();
}

private Payment.TypeEnum toDomainPaymentType(CreatePayment.TypeEnum createPaymentType) {
String feeType = createPaymentType.toString();
if (feeType.equals(Payment.TypeEnum.CASH.toString())) {
return Payment.TypeEnum.CASH;
} else if (feeType.equals(Payment.TypeEnum.SCOLARSHIP.toString())) {
return Payment.TypeEnum.SCOLARSHIP;
} else if (feeType.equals(Payment.TypeEnum.FIX.toString())) {
return Payment.TypeEnum.FIX;
}
throw new BadRequestException("Payment type must be valid");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ protected void configure(HttpSecurity http) throws Exception {
.antMatchers(GET, "/students/*/fees/*").hasAnyRole(MANAGER.getRole())
.antMatchers(POST, "/students/*/fees").hasAnyRole(MANAGER.getRole())
.requestMatchers(new SelfMatcher(GET, "/students/*/fees")).hasAnyRole(STUDENT.getRole())
.requestMatchers(new SelfMatcher(GET, "/students/*/fees/*/payments")).hasAnyRole(STUDENT.getRole())
.antMatchers(GET, "/students/*/fees/*/payments").hasAnyRole(MANAGER.getRole())
.antMatchers(POST, "/students/*/fees/*/payments").hasAnyRole(MANAGER.getRole())
.antMatchers(GET, "/students/*/fees").hasAnyRole(MANAGER.getRole())
.requestMatchers(new SelfMatcher(GET, "/students/*")).hasAnyRole(STUDENT.getRole())
.antMatchers(GET, "/students/*").hasAnyRole(TEACHER.getRole(), MANAGER.getRole())
Expand Down
70 changes: 70 additions & 0 deletions src/main/java/school/hei/haapi/model/Payment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package school.hei.haapi.model;

import java.io.Serializable;
import java.time.Instant;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.Hibernate;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import school.hei.haapi.repository.types.PostgresEnumType;

import static javax.persistence.GenerationType.IDENTITY;

@Entity
@Table(name = "\"payment\"")
@Getter
@Setter
@TypeDef(name = "pgsql_enum", typeClass = PostgresEnumType.class)
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
private String id;

private String feeId;

@Type(type = "pgsql_enum")
@Enumerated(EnumType.STRING)
private school.hei.haapi.endpoint.rest.model.Payment.TypeEnum type;

private int amount;
private String comment;
@CreationTimestamp private Instant creationDatetime;

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) {
return false;
}
Payment payment = (Payment) o;
return amount == payment.amount
&& Objects.equals(id, payment.id)
&& Objects.equals(feeId, payment.feeId)
&& type == payment.type
&& creationDatetime.compareTo(payment.creationDatetime) == 0;
}

@Override
public int hashCode() {
return getClass().hashCode();
}
}
18 changes: 18 additions & 0 deletions src/main/java/school/hei/haapi/repository/PaymentRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package school.hei.haapi.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import school.hei.haapi.model.Payment;

@Repository
public interface PaymentRepository extends JpaRepository<Payment, String> {
List<Payment> getByFeeId(String feeId);

@Query(value = "select p.* from payment p join fee f on f.id = p.fee_id"
+ " where f.user_id = :student_id",
nativeQuery = true)
List<Payment> getByStudentId(@Param("student_id") String studentId);
}
26 changes: 26 additions & 0 deletions src/main/java/school/hei/haapi/service/PaymentService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package school.hei.haapi.service;

import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import school.hei.haapi.model.Payment;
import school.hei.haapi.repository.PaymentRepository;

@Service
@AllArgsConstructor
public class PaymentService {

private final PaymentRepository paymentRepository;

public List<Payment> getByStudentIdAndFeeId(String studentId, String feeId) {
return paymentRepository.getByFeeId(feeId);
}

public List<Payment> getByStudentId(String studentId) {
return paymentRepository.getByStudentId(studentId);
}

public List<Payment> saveAll(String studentId, String feeId, List<Payment> toCreate) {
return paymentRepository.saveAll(toCreate);
}
}
21 changes: 21 additions & 0 deletions src/main/resources/db/migration/V0_4__Create_payment_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
do
$$
begin
if not exists(select from pg_type where typname = 'payment_type') then
create type "payment_type" as enum ('CASH', 'SCHOLARSHIP','FIX');
end if;
end
$$;

create table if not exists "payment"
(
id varchar
constraint payment_pk primary key default uuid_generate_v4(),
fee_id varchar not null
constraint payment_fee_id_fk references "fee"(id),
type payment_type not null,
amount integer not null,
comment varchar not null,
creation_datetime timestamp with time zone not null default now()
);
create index if not exists payment_fee_id_index on "payment" (fee_id);
4 changes: 4 additions & 0 deletions src/main/resources/db/testdata/V99_3__Test_create_fees.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ insert into "fee"
(id, user_id, status, type, comment,total_amount, remaining_amount, creation_datetime, due_datetime)
values
('fee1_id', 'student1_id', 'UNPAID', 'TUITION','Comment', 5000, 5000, '2021-11-08T08:25:24.00Z', '2021-12-08T08:25:24.00Z');
insert into "fee"
(id, user_id, status, type, comment,total_amount, remaining_amount, creation_datetime, due_datetime)
values
('fee2_id', 'student2_id', 'UNPAID', 'TUITION','Comment', 5000, 5000, '2022-12-08T08:25:24.00Z', '2021-12-31T08:25:24.00Z');
4 changes: 0 additions & 4 deletions src/main/resources/db/testdata/V99_4__Test_create_fees.sql

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
insert into "payment"
(id, fee_id, type, comment,amount, creation_datetime)
values
('payment1_id','fee1_id', 'CASH', 'Comment', 2000, '2021-11-08T08:25:24.00Z');
insert into "payment"
(id, fee_id, type, comment,amount, creation_datetime)
values
('payment2_id','fee2_id', 'CASH', 'Comment', 2000, '2021-11-08T08:25:24.00Z');
Loading

0 comments on commit 88467cb

Please sign in to comment.