Skip to content
Snippets Groups Projects
Commit 81488337 authored by Yokiza's avatar Yokiza
Browse files

Merge branch 'develop' into main

parents 6e613a2a dc60ca7d
Branches
No related tags found
No related merge requests found
Pipeline #230254 passed
Showing
with 1262 additions and 2 deletions
# Defining the stages for the pipeline
stages:
- login
- build
- tagging
- publish
- deploy
# Defining the variables that can be used in the pipeline
variables:
DOCKER_VERSION: 23.0.4
DIND_VERSION: 23.0.4-dind
ALPINE_VERSION: 3.17.3
MAVEN_VERSION: 3.8.5-openjdk-18
IMAGE_NAME: query-engine-backend-image
REPOSITORY_NAME: query_engine
SSH_KEY: $ID_RSA_PRIVATE
MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
CONTAINER_NAME: "spring"
SERVER_PORT: 8080
# Added cache
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- /usr/local/share/ca-certificates/
- /var/lib/docker
# Defining the docker login stage
docker-login:
stage: login
image: docker:$DOCKER_VERSION
script:
- echo "Logging in to Docker"
- docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
# Defining the build stage
maven-build:
stage: build
image: maven:$MAVEN_VERSION
script:
- echo "Compiling"
- mvn package -B
artifacts:
paths:
- target/*.jar
# Defining the package stage
maven-package:
stage: build
image: maven:$MAVEN_VERSION
script:
- echo "Packaging"
- mvn $MAVEN_OPTS clean package
artifacts:
paths:
- target/*.jar
# Defining the docker build stage
docker-build:
image: docker:$DOCKER_VERSION
stage: build
services:
- docker:dind
variables:
DOCKER_TLS_CERTDIR: ""
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375/
dependencies:
- maven-package
before_script:
- docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
script:
- echo "Building docker image"
- docker build -t $REPOSITORY_NAME .
needs:
- maven-package
# Defining the docker tag stage
docker-tag:
stage: tagging
image: docker:$DOCKER_VERSION
script:
- echo "Tagging the docker image ${REPOSITORY_NAME} as ${DOCKER_USERNAME}/${IMAGE_NAME}"
- docker tag ${REPOSITORY_NAME} ${DOCKER_USERNAME}/${IMAGE_NAME}
needs:
- docker-build
# Defining the docker push stage
docker-push-to-docker-hub:
stage: publish
image: docker:$DOCKER_VERSION
variables:
DOCKER_TLS_CERTDIR: ""
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375/
services:
- "docker:dind"
before_script:
- echo "Authenticating with docker"
- docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
- echo "Building docker image"
- docker build -t $REPOSITORY_NAME .
- echo "Tagging the docker image ${REPOSITORY_NAME} as ${DOCKER_USERNAME}/${IMAGE_NAME}"
- docker tag ${REPOSITORY_NAME} ${DOCKER_USERNAME}/${IMAGE_NAME}
script:
- echo "Pushing the docker image to docker hub as ${DOCKER_USERNAME}/${IMAGE_NAME}"
- docker push ${DOCKER_USERNAME}/${IMAGE_NAME}
needs:
- docker-tag
# Defining the deploy stage
push-to-server:
image: debian:11.6-slim
stage: deploy
tags:
- deployment
script:
- apt-get update && apt-get install -y openssh-client
- chmod og= $SSH_KEY
- ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD"
- ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull ${DOCKER_USERNAME}/${IMAGE_NAME}"
- ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker stop $CONTAINER_NAME || true"
- ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f $CONTAINER_NAME || true"
- ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f $IMAGE_NAME || true"
- ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run --name $CONTAINER_NAME -d -p $SERVER_PORT:$SERVER_PORT ${DOCKER_USERNAME}/${IMAGE_NAME}"
environment:
name: production
url: $SERVER_IP
needs:
- docker-push-to-docker-hub
\ No newline at end of file
# Build stage
FROM openjdk:17-jdk-slim-buster as builder
# Setting the working directory directory
WORKDIR /app
# Copy maven wrapper files
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
RUN ./mvnw dependency:go-offline
COPY src src
RUN ./mvnw package
# Production stage
FROM openjdk:17-jdk-slim-buster as production-stage
# Set working directory
WORKDIR /app
RUN apt-get update && apt-get install -y git
# Copy the built Jar file from build-stage
COPY --from=builder /app/target/*.jar app.jar
# Exposes the port
EXPOSE 8080
# Set the entrypoint to run the application
ENTRYPOINT ["java", "-jar", "app.jar" ]
# READ ME! # <ins>README - Query Engine and Viewer</ins>
Bachelor thesis developed in collaboration with Postnord. The purpose of the project
is to create a simple web application for extracting data in a simple manner
without having to know SQL as a prerequisite.
## Why this project
Extracting data from a database can be a time-consuming and expensive process. To
free up developers to focus on writing code and implement new features instead,
this page is created. In this manner both administrators and developers can access
data quickly, leaving more time for coding and other activities.
##
## installation
Application runs in the web on a browser, so no other tools are needed. (The
is meant for desktop computers, and will not scale for tablets, phones, or
other devices).
...@@ -55,8 +55,24 @@ ...@@ -55,8 +55,24 @@
<artifactId>hibernate-community-dialects</artifactId> <artifactId>hibernate-community-dialects</artifactId>
<version>6.1.7.Final</version> <version>6.1.7.Final</version>
</dependency> </dependency>
</dependencies> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.5.1</version>
</dependency>
</dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
......
...@@ -2,6 +2,9 @@ package no.ntnu.queryeng; ...@@ -2,6 +2,9 @@ package no.ntnu.queryeng;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@SpringBootApplication @SpringBootApplication
public class QueryengApplication { public class QueryengApplication {
...@@ -10,4 +13,26 @@ public class QueryengApplication { ...@@ -10,4 +13,26 @@ public class QueryengApplication {
SpringApplication.run(QueryengApplication.class, args); SpringApplication.run(QueryengApplication.class, args);
} }
/**
* Represents a configurer for the cors.
*
* @return a configurer for the cors.
*/
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
corsRegistry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(false)
.maxAge(-1);
}
};
}
} }
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.entity.Customer;
import no.ntnu.queryeng.queryEntity.CityWithCustomers;
import no.ntnu.queryeng.queryEntity.PostCodeCustomer;
import no.ntnu.queryeng.repository.CustomerRepo;
import no.ntnu.queryeng.repository.PostCodeCustomerRepo;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import java.util.List;
/**
* Represents customer controller with queries to fetch required information.
*/
@Controller
public class CustomerController {
private CustomerRepo customerRepo;
private PostCodeCustomerRepo postCodeCustomerRepo;
public CustomerController(CustomerRepo customerRepo, PostCodeCustomerRepo postCodeCustomerRepo) {
this.customerRepo = customerRepo;
this.postCodeCustomerRepo = postCodeCustomerRepo;
}
/**
* Query to find all customers in the database
*
* @return list of all customers
*/
@QueryMapping
List<Customer> getAllCustomers() {
return customerRepo.findAllByLimit();
}
/**
* Query to find customers matching the following parameters
*
* @param fname first name of the customer
* @param lname last name of the customer
* @param pCity city of the customer
* @param mob mobile number of the customer
* @param mail email address of the customer
* @param pCode post code of the customer
* @return list of customers matching the parameters
*/
@QueryMapping
List<Customer> getCustomersByName(@Argument String fname,
@Argument String lname,
@Argument String pCode,
@Argument String pCity,
@Argument String mob,
@Argument String mail) {
return customerRepo.findAllByName(fname, lname, pCity, mob, mail, pCode);
}
/**
* Get the largest post code in the database.
*
* @return the largest post code object with the largest post code and the
* count.
*/
@QueryMapping
PostCodeCustomer getLargestPostCode() {
return postCodeCustomerRepo.findLargestPostCode();
}
/**
* Get the smallest post code in the database.
*
* @return the smallest post code object with the smallest post code and the
* count.
*/
@QueryMapping
PostCodeCustomer getSmallestPostCode() {
return postCodeCustomerRepo.findSmallestPostCode();
}
/**
* Get all post codes in the database.
*
* @return all post codes in the database
*/
@QueryMapping
List<PostCodeCustomer> getAllPostCodes() {
return postCodeCustomerRepo.findAllPostCode();
}
@QueryMapping
List<CityWithCustomers> getAllCitiesWithCustomers() {
return customerRepo.findAllCitiesWithCustomers();
}
/**
* Total customers registered in the database.
*
* @return total customers registered in the database
*/
@QueryMapping
int getTotalCustomers() {
return customerRepo.countCustomers();
}
}
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.entity.Invoice;
import no.ntnu.queryeng.repository.InvoiceRepo;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import java.sql.Date;
import java.util.List;
@Controller
public class InvoiceController {
private InvoiceRepo invoiceRepo;
public InvoiceController (InvoiceRepo invoiceRepo) { this.invoiceRepo = invoiceRepo; }
// Default test query to figure out if the GraphQL queries work as intended
@QueryMapping
public Invoice getInvoiceById(@Argument int id) { return invoiceRepo.getInvoiceById(id); }
@QueryMapping
public List<Invoice> getAllInvoices () { return invoiceRepo.findAllByLimit();}
/**
* Fetches the amount of invoices as a number
* @return the amount of invoices as an integer
*/
@QueryMapping
public Integer getNumberOfInvoices () { return invoiceRepo.getNumberOfInvoices(); }
@QueryMapping
public Integer getSumOfParcels() {
return invoiceRepo.getSumShippingCostOfParcel();
}
/**
* Returns all the invoices between given date range
* @param startDate start date to search from
* @param endDate last date to search to
* @return list of invoices
*/
@QueryMapping
public List<Invoice> getInvoiceByDateRange(@Argument Date startDate, @Argument Date endDate){
return invoiceRepo.getInvoiceByDateRange(startDate, endDate);
}
/**
* Returns total unpaid amount from the invoices
* @return unpoid amount
*/
@QueryMapping
public int getUnPaidAmount(){
return invoiceRepo.getTotalUnpaidAmount();
}
}
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.entity.Parcel;
import no.ntnu.queryeng.repository.ParcelRepository;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import java.util.List;
/**
* This class takes use of GraphQL for making queries using the notation: @QueryMapping and @SchemaMapping
*/
@Controller
public class ParcelController {
private ParcelRepository parcelRepository;
public ParcelController(ParcelRepository parcelRepository) {
this.parcelRepository = parcelRepository;
}
@QueryMapping
public Parcel parcelById(@Argument long id) {
return parcelRepository.getById(id);
}
@QueryMapping
public List<Parcel> parcelsByGivenStatus(@Argument int statusId) {
return parcelRepository.getParcelsByStatusCode(statusId);
}
@QueryMapping
public int getSumShippingCostOfParcel() {
return parcelRepository.getSumShippingCostOfParcel();
}
}
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.queryEntity.ParcelCustomer;
import no.ntnu.queryeng.repository.ParcelCustomerRepo;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import java.util.List;
@Controller
public class ParcelCustomerController {
public ParcelCustomerController(ParcelCustomerRepo parcelCustomerRepo) {
this.parcelCustomerRepo = parcelCustomerRepo;
}
private ParcelCustomerRepo parcelCustomerRepo;
/**
* Total customers grouped according to number of parcels sent.
*
* @return total customers sort after number of parcels
*/
@QueryMapping
List<ParcelCustomer> getTotalCustomersPerParcel() {
return parcelCustomerRepo.findCustomersCountPerParcel();
}
}
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.entity.Scan;
import no.ntnu.queryeng.entity.Terminal;
import no.ntnu.queryeng.repository.ScanRepository;
import no.ntnu.queryeng.repository.TerminalRepo;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import java.sql.Date;
import java.util.List;
@Controller
public class ScanController {
// creates a instance of scanRepository as a variable
private ScanRepository scanRepository;
/**
* Creates an instance and Initiates the ScanController class
* @param scanRepository //ToDo: Define
*/
public ScanController(ScanRepository scanRepository) {
this.scanRepository = scanRepository;
}
/**
* A query for fetching a scan by its ID
* @param id the id to search for
* @return the scan with the given id
*/
@QueryMapping
public Scan scanById(@Argument int id) {
return scanRepository.getById(id);
}
/**
* A Query for fetching a list of scans with a given status message
* Examples: status_id indexed by number 1 = "ARRIVED"
* Examples: status_id indexed by number 2 = "PICKED"
* Examples: status_id indexed by number 3 = "UNDER TRANSPORT"
*
* @return returns a list of scans with a status message filtered by the status messages id
*/
@QueryMapping
public List<Scan> fetchAllScans() {return scanRepository.getAllScans();}
@QueryMapping
public List<Scan> fetchScansByYear(@Argument String year){
return scanRepository.getAllScansByYear(year);
}
@QueryMapping
public List<Scan> fetchScansByDateRange(@Argument Date startDate, @Argument Date endDate){
return scanRepository.getAllScansByDateLimit(startDate, endDate);
}
@QueryMapping
public int fetchScansCountByDateRange(@Argument Date startDate, @Argument Date endDate){
return scanRepository.getAllScansCountByDateLimit(startDate, endDate);
}
}
\ No newline at end of file
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.entity.Scan;
import no.ntnu.queryeng.entity.ShippingOrder;
import no.ntnu.queryeng.entity.Terminal;
import no.ntnu.queryeng.repository.ShippingOrderRepository;
import no.ntnu.queryeng.service.ShippingOrderService;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import java.util.List;
/**
* This class takes use of GraphQL for making queries using the notation: @QueryMapping and @SchemaMapping
* //ToDo: Fill in a more complete Description of the class
* //TODO: borrowed some of odins documentation until we know
* //TODO: which methods and classes that are supposed to be used. will replace documentation later.
*
* @author Joakim
* @version 0.0.1
*/
@Controller
public class ShippingOrderController {
/**
* Fetches the "type query" defined in resoruces/graphql/schema.graphqls in order to fetch the ShippingOrder
* of a given id (an int), if found it returns the ShippingOrder with the id matching the id requested.
* Example: input 1, output (1, "Arrived")
*
* @param id the integer value of the ShippingOrder you wish to search for
* @return the ShippingOrder with the matching id
*
@QueryMapping
public ShippingOrderService ShippingOrderById(@Argument int id) {
return ShippingOrderService.getById(id);
} */
private ShippingOrderRepository shippingOrderRepository;
public ShippingOrderController (ShippingOrderRepository shippingOrderRepository) { this.shippingOrderRepository = shippingOrderRepository; }
@QueryMapping
public ShippingOrder shippingOrderById (@Argument int id) {
return shippingOrderRepository.getById(id);
}
@QueryMapping
public List<ShippingOrder> fetchAllShippingOrders(){
return (List<ShippingOrder>) shippingOrderRepository.findAll();
}
}
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.entity.Status;
import no.ntnu.queryeng.entity.Terminal;
import no.ntnu.queryeng.repository.StatusRepo;
import no.ntnu.queryeng.repository.TerminalRepo;
import no.ntnu.queryeng.service.StatusService;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import java.util.List;
/**
* This class takes use of GraphQL for making queries using the notation: @QueryMapping and @SchemaMapping
* //ToDo: Fill in a more complete Description of the class
*
* @author odin
* @version 1.0.0
*/
@Controller
public class StatusController {
private StatusRepo statusRepo;
public StatusController(StatusRepo statusRepo) {
this.statusRepo = statusRepo;
}
/**
* Fetches the "type query" defined in resoruces/graphql/schema.graphqls in order to fetch the Status
* of a given id (an int), if found it returns the status with the id matching int requested.
* Example: input 1, output (1, "Arrived")
*
* @param id the integer value of the status you wish to search for
* @return the status with the matching id
*/
@QueryMapping
public Status statusById(@Argument int id) {
return statusRepo.getById(id);
}
/**
* Gets all statuses
* @return returns a list of status
*/
@QueryMapping
public List<Status> getAllStatus() {
return (List<Status>) statusRepo.findAll();
}
}
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.entity.Terminal;
import no.ntnu.queryeng.repository.TerminalRepo;
import no.ntnu.queryeng.service.TerminalService;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.data.method.annotation.SchemaMapping;
import org.springframework.stereotype.Controller;
import java.util.List;
/**
* This class takes use of GraphQL for making queries using the notation: @QueryMapping and @SchemaMapping
* //ToDo: Fill in a more complete Description of the class
*
* @author odin
* @version 1.1.0
*/
@Controller
public class TerminalController {
private TerminalRepo terminalRepo;
public TerminalController(TerminalRepo terminalRepo) {
this.terminalRepo = terminalRepo;
}
/**
* Fetches the "type query" defined in resoruces/graphql/schema.graphqls in order to fetch the Terminal
* of a given id (an int), if found it returns the terminal with the id matching int requested.
* Example: input 1, output (1, "Orsta", "Haakonsgata 23", 50)
*
* @param id the integer value of the terminal you wish to search for
* @return the terminal with the matching id
*/
@QueryMapping
public Terminal terminalById(@Argument int id) {
return terminalRepo.getById(id);
}
@QueryMapping
public Terminal terminalByName(@Argument String name) {
return terminalRepo.findTerminalByName(name);
}
@QueryMapping
public List<Terminal> fetchAllTerminals(){ return (List<Terminal>) terminalRepo.findAll();
}
}
package no.ntnu.queryeng.controller;
import no.ntnu.queryeng.repository.TerminalScanCostRepository;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
@Controller
public class TerminalScanCostController {
private TerminalScanCostRepository terminalScanCostRepository;
public TerminalScanCostController(TerminalScanCostRepository terminalScanCostRepository) {
this.terminalScanCostRepository = terminalScanCostRepository;
}
/**
* Returns the total cost of all scans for all terminals
* @return total costs of all scans for all terminals
*/
@QueryMapping
Integer getScanCostForAllTerminals() {
return this.terminalScanCostRepository.getTotalCostOfScans();
}
}
package no.ntnu.queryeng.dummydata;
import com.opencsv.CSVWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
/**
* Populates dummy data to use in barcode table in PostNord database.
*/
public class BarCodeDummyData {
public static void main(String[] args) throws IOException {
Random rand = new Random();
// Using hashset to make sure barcodes are unique
Set<String> barcodes = new HashSet<>();
List<String[]> data = new ArrayList<>();
String[] header = {"id", "barcode", "in_use"};
int id = 1;
while (barcodes.size() < 1000000) {
StringBuilder sb = new StringBuilder();
// Adds 70 to indicate that barcodes represents postal service.
sb.append("70");
for (int i = 0; i < 21; i++) {
sb.append(rand.nextInt(10));
}
String barcode = sb.toString();
boolean value = true;
if (barcodes.size() >= 750000) {
value = false;
}
String[] row = {Integer.toString(id), barcode, Boolean.toString(value)};
barcodes.add(barcode);
data.add(row);
id++;
}
// Writes the populated data to a csv file
CSVWriter writer = new CSVWriter(new FileWriter("barcode.csv"));
writer.writeNext(header);
writer.writeAll(data);
writer.close();
}
}
package no.ntnu.queryeng.dummydata;
import com.github.javafaker.Address;
import com.github.javafaker.Faker;
import com.opencsv.CSVWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
/**
* Populates dummy customer data to use in customer table in PostNord database.
*/
public class CustomerDummyData {
private static final int NUM_ORDERS = 10;
public static void main(String[] args) throws IOException {
Faker faker = new Faker(new Locale("nb-NO"));
String[] header = {"id","first_name","last_name","address","post_code","city","mobile","email"};
List<String[]> data = new ArrayList<>();
int id = 1;
while (id < NUM_ORDERS) {
String firstName = faker.name().firstName();
String lastName = faker.name().lastName();
Address address = faker.address();
String streetAddress = generateStreetAddress(faker);
String postalCode = generateNorwegianPostalCode(faker);
String city = address.city();
String mobile;
// Makes sure that mobile numbers are of length 8, and do not
// start with 0 and 1.
do {
mobile = faker.phoneNumber().subscriberNumber(8);
} while (mobile.length() != 8 || mobile.startsWith("0") || mobile.startsWith("1"));
// Generates unique email address
String email = faker.internet().emailAddress(firstName.toLowerCase() + "." + lastName.toLowerCase() + UUID.randomUUID().toString().replace("-", "").substring(0, 12));
String[] row = {String.valueOf(id),firstName,lastName,streetAddress, postalCode, city, mobile,email};
data.add(row);
id++;
}
// Writes created data to a csv file.
CSVWriter writer = new CSVWriter(new FileWriter("customer.csv"));
writer.writeNext(header);
writer.writeAll(data);
writer.close();
}
/**
* Generates postal code that resembles norwegian post codes
* @param faker an instance of Faker
* @return post code
*/
private static String generateNorwegianPostalCode(Faker faker) {
// Generate a random 4-digit number between 1000 and 9999
int postalCode = faker.number().numberBetween(1000, 6666);
return String.format("%04d", postalCode);
}
/**
* Generates street address
* @param faker an instance of Faker
* @return street address
*/
private static String generateStreetAddress(Faker faker) {
String streetAddress;
do {
streetAddress = faker.address().streetAddress();
} while (streetAddress.endsWith("0"));
return streetAddress;
}
}
\ No newline at end of file
package no.ntnu.queryeng.dummydata;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
/**
* Populating dummy parcel data to use in parcel table in PostNord database
*/
public class ParcelDummyData {
public static void main(String[] args) {
Random random = new Random();
try {
FileWriter writer = new FileWriter("parcel.csv");
writer.write("id,weight,shipping_order_id,shipping_cost_id,barcode_id\n");
Set<Integer> usedBarcodeIds = new HashSet<>();
// a Map to keep track of the number of times each shipping order ID has been used
Map<Integer, Integer> shippingOrderCounts = new HashMap<>();
// Generating 750000 dummy data
for (int i = 1; i <= 750000; i++) {
int weight;
int weightCategory = random.nextInt(100);
if (weightCategory < 90) {
// 90% of the time, generate weight between 1 and 100 kg
weight = random.nextInt(100) + 1;
} else if (weightCategory < 99) {
// 9% of the time, generate weight between 101 and 1000 kg
weight = random.nextInt(900) + 101;
} else {
// 1% of the time, generate weight between 1001 and 2600 kg
weight = random.nextInt(1600) + 1001;
}
int shippingOrderId;
int shippingOrderCount;
do {
shippingOrderId = random.nextInt(750000) + 1;
shippingOrderCount = shippingOrderCounts.getOrDefault(shippingOrderId, 0);
} while (shippingOrderCount >= (random.nextInt(5) + 1));
shippingOrderCounts.put(shippingOrderId, shippingOrderCount + 1);
// Generates only unique barcode ids.
int barcodeId;
do {
barcodeId = random.nextInt(750000) + 1;
} while (usedBarcodeIds.contains(barcodeId));
usedBarcodeIds.add(barcodeId);
// Setting cost id according to the weight of the parcel
int shippingCostId;
if (weight <= 2) {
shippingCostId = 1;
} else if (weight <= 20) {
shippingCostId = 2;
} else if (weight <= 35) {
shippingCostId = 3;
} else if (weight <= 1000) {
shippingCostId = 4;
} else if (weight <= 2500) {
shippingCostId = 5;
} else {
shippingCostId = 6;
}
writer.write(i + "," + weight + "," + shippingOrderId + "," + shippingCostId + "," + barcodeId + "\n");
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package no.ntnu.queryeng.dummydata;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Date;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Random;
import com.github.javafaker.Faker;
/**
* Populates shipping order and invoice test data to use in PostNord database.
*/
public class ShippingOrderDummyData {
// Initializing constants
private static final int NUM_ORDERS = 750000;
private static final int MIN_CUSTOMER_ID = 1;
private static final int MAX_CUSTOMER_ID = 500000;
private static final double PAID_PROBABILITY = 0.7;
private static final int SENDER = 1;
private static final int RECEIVER = 2;
private static final int THIRD_PARTY = 3;
public static void main(String[] args) throws IOException {
Random rand = new Random();
Faker faker = new Faker();
// Creating files and headers to write test data.
FileWriter shippingOrderWriter = new FileWriter("shipping_orders.csv");
shippingOrderWriter.write("id,sender_id,receiver_id,created_at\n");
FileWriter invoiceWriter = new FileWriter("invoices.csv");
invoiceWriter.write("id,shipping_order_id,customer_id,third_party_id,payer_type_id,created_at,due_date,is_paid\n");
// Populates given number of invoices and shipping order.
for (int i = 1; i <= NUM_ORDERS; i++) {
int orderId = i;
// Populating sender id withing the range of customer data.
int senderId = rand.nextInt(MAX_CUSTOMER_ID - MIN_CUSTOMER_ID + 1) + MIN_CUSTOMER_ID;
int receiverId;
// Ensures that sender id and receiver id is not same.
do {
receiverId = rand.nextInt(MAX_CUSTOMER_ID - MIN_CUSTOMER_ID + 1) + MIN_CUSTOMER_ID;
} while (receiverId == senderId);
// Populates dates between given interval.
LocalDate shippingOrderDate = faker.date().between(Date.valueOf("2022-04-25"), Date.valueOf("2023-04-25")).toInstant().atZone(ZoneId.of(faker.address().timeZone())).toLocalDate();
String strShippingOrderDate = shippingOrderDate.toString();
// Writing data to file
shippingOrderWriter.write(orderId + "," + senderId + "," + receiverId + "," + strShippingOrderDate + "\n");
// Setting due date to be 3 weeks after created_at date.
LocalDate dueDate = shippingOrderDate.plusWeeks(3);
// Setting default values to use when the value is empty
String customerId = "0";
String thirdParty = "0";
int payerType;
double selectionChance = rand.nextDouble();
if (selectionChance < 0.35) {
customerId = String.valueOf(senderId);
payerType = SENDER;
} else if (selectionChance < 0.7) {
customerId = String.valueOf(receiverId);
payerType = RECEIVER;
} else {
// Sets a random value between 1 to 10, as PostNord has 10 third party entries.
thirdParty = String.valueOf(rand.nextInt(10) + 1);
payerType = THIRD_PARTY;
}
// Ensures that 70% of invoices are set to true.
boolean isPaid = rand.nextDouble() < PAID_PROBABILITY;
invoiceWriter.write(orderId + "," + orderId + "," + customerId + "," + thirdParty + "," + payerType + "," + shippingOrderDate + "," + dueDate + "," + isPaid + "\n");
}
shippingOrderWriter.close();
invoiceWriter.close();
System.out.println("Files are created successfully!");
}
}
package no.ntnu.queryeng.entity;
import jakarta.persistence.*;
import no.ntnu.queryeng.tools.InputChecker;
/**
* Class represents additional service that can be added to a shipping order.
*
* @author aleksander & Joakim Røren Melum
* @version 0.1
* @date 25.04.2023
*/
@Entity
@Table(name = "additional_service")
public class AdditionalService {
/**
* The unique id of the additional service.
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
/**
* The additional service name of the additional service.
*/
@Column(name = "additional_service")
private String additionalServiceName;
/**
* The description of the additional service.
*/
@Column(name = "description")
private String description;
/**
* The cost of the additional service.
*/
@Column(name = "cost")
private double cost;
/**
* The additional service order connected to the additional service.
*/
@OneToOne
@JoinColumn(name = "additional_service_order_id") //TODO: FIX THIS!
private AdditionalServiceOrder additionalServiceOrder;
/**
* No argument constructor for additional service. Intentionally left empty.
*/
public AdditionalService() {
}
/**
* Constructs an instance of this class
*
* @param additionalServiceName the name of the additional service
* @param description description of additional service
* @param cost cost of the additional service
* @throws IllegalArgumentException if some inputs is not correct.
*/
public AdditionalService(int id, String additionalServiceName, String description, double cost) {
if (InputChecker.isValid(additionalServiceName) && InputChecker.isValid(description) && InputChecker.isValid(cost) && InputChecker.isValid(id)) {
this.id = id;
this.additionalServiceName = additionalServiceName;
this.description = description;
this.cost = cost;
} else {
throw new IllegalArgumentException("Invalid input");
}
}
/**
* Return the additional service's id.
* @return the additional service's id.
*/
public int getId() {
return id;
}
/**
* Return the additional service's name.
* @return the additional service's name.
*/
public String getAdditionalServiceName() {
return additionalServiceName;
}
/**
* Return the additional service's description.
* @return the additional service's description.
*/
public String getDescription() {
return description;
}
/**
* Return the additional service's cost.
* @return the additional service's cost.
*/
public double getCost() {
return cost;
}
/**
* Return the additional service order connected to the additional service.
* @return the additional service order connected to the additional service.
*/
public AdditionalServiceOrder getAdditionalServiceOrder() {
return this.additionalServiceOrder;
}
}
package no.ntnu.queryeng.entity;
import jakarta.persistence.*;
import no.ntnu.queryeng.tools.InputChecker;
import java.time.LocalDateTime;
/**
* This class represents an additional service invoice in the system.
* An additional service invoice contains the following about what
* additional services that is placed on the order. Who is the invoice
* payer, the date it was created and due date of the invoice.
* It also contains information that tells if the invoice is
* paid or not.
*
* @author aleksander & Joakim Røren Melum
* @version 0.1
* @date 25.04.2023
*/
@Entity
@Table(name = "additional_service_invoice")
public class AdditionalServiceInvoice {
/**
* The additional service invoice's ID.
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
/**
* The additional service invoice's linked additional service order.
*/
@OneToOne(mappedBy = "additionalServiceInvoice")
private AdditionalServiceOrder additionalServiceOrder;
/**
* The additional service invoice's linked customer.
*/
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
/**
* The additional service invoice's linked third party.
*/
@ManyToOne()
@JoinColumn(name = "third_party_id")
private ThirdParty thirdParty;
/**
* The additional service invoice's payer type.
*/
@ManyToOne
@JoinColumn(name = "payer_type_id")
private InvoicePayerType invoicePayerType;
/**
* The additional service invoice's created at.
*/
@Column(name = "created_at")
private LocalDateTime createdAt;
/**
* The additional service invoice's.
*/
@Column(name = "due_date")
private LocalDateTime dueDate;
/**
* The additional service invoice's.
*/
@Column(name = "is_paid")
private boolean isPaid;
/**
* Creates an instance of this class.
*
* @param id the additional service invoice's id.
* @param additionalServiceOrder the additional service order.
* @param createdAt the time and date the invoice is created.
* @param dueDate the date the invoice the is due.
* @param isPaid indicates if the invoice is paid or not.
*/
public AdditionalServiceInvoice(int id, AdditionalServiceOrder additionalServiceOrder,
LocalDateTime createdAt, LocalDateTime dueDate,
boolean isPaid) {
if (InputChecker.isValid(id) && additionalServiceOrder != null && createdAt != null && dueDate != null) {
this.id = id;
this.additionalServiceOrder = additionalServiceOrder;
this.createdAt = createdAt.now();
this.dueDate = dueDate;
this.isPaid = isPaid;
} else {
throw new IllegalArgumentException("Invalid input");
}
}
/**
* No args constructor. Intentionally left empty.
*/
public AdditionalServiceInvoice() {
}
/**
* Return the ID of the additional service invoice.
* @return the ID of the additional service invoice.
*/
public int getId() {
return id;
}
/**
* Return the linked additional service order.
* @return the linked additional service order.
*/
public AdditionalServiceOrder getAdditionalServiceOrder() {
return additionalServiceOrder;
}
/**
* Return the linked customer id.
* @return the linked customer id.
*/
public Customer getCustomerId() {
return customer;
}
/**
* Return the linked third party.
* @return the linked third party.
*/
public ThirdParty getThirdParty() {
return thirdParty;
}
/**
* Return the linked invocie payer type id.
* @return the linked invocie payer type id.
*/
public InvoicePayerType getInvoicePayerTypeId() {
return invoicePayerType;
}
/**
* Return the date and time the additional service invoice was created at.
* @return the date and time the additional service invoice was created at.
*/
public LocalDateTime getCreatedAt() {
return createdAt;
}
/**
* Return the date and time the additional service invoice is due at.
* @return the date and time the additional service invoice is due at.
*/
public LocalDateTime getDueDate() {
return dueDate;
}
/**
* Return if the additional service invoice is paid or not.
* @return if the additional service invoice is paid or not.
*/
public boolean isPaid() {
return isPaid;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment