Added CRUD for 'Orders' entity, formatters, translations. Removed useless service.

This commit is contained in:
Alexey Zinchenko 2019-05-05 20:39:28 +03:00
parent 0124899525
commit 5f15555f4e
22 changed files with 508 additions and 53 deletions

View File

@ -20,3 +20,4 @@ public class CarRepairApplication {
// TODO: i18n
// TODO: tests
// TODO: big data
// TODO: add autocomplete

View File

@ -0,0 +1,106 @@
package com.github.prominence.carrepair.controller;
import com.github.prominence.carrepair.enums.OrderStatus;
import com.github.prominence.carrepair.model.Order;
import com.github.prominence.carrepair.service.ClientService;
import com.github.prominence.carrepair.service.MechanicService;
import com.github.prominence.carrepair.service.OrderService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.Optional;
@Controller
@RequestMapping(value = "/order")
public class OrderController {
private OrderService orderService;
private ClientService clientService;
private MechanicService mechanicService;
public OrderController(OrderService orderService, ClientService clientService, MechanicService mechanicService) {
this.orderService = orderService;
this.clientService = clientService;
this.mechanicService = mechanicService;
}
@GetMapping
public String index(ModelMap modelMap) {
Page<Order> orderList = orderService.findAll((Pageable) modelMap.get("pagination"));
modelMap.addAttribute("orderList", orderList.getContent());
modelMap.addAttribute("totalPages", orderList.getTotalPages());
return "order/index";
}
@GetMapping(value = "/create")
public String create(Model model) {
model.addAttribute("order", new Order());
model.addAttribute("clientIdsList", clientService.getAllClientIds());
model.addAttribute("mechanicIdsList", mechanicService.getAllMechanicIds());
model.addAttribute("orderStatuses", new OrderStatus[] { OrderStatus.SCHEDULED, OrderStatus.DONE, OrderStatus.ACCEPTED });
return "order/edit";
}
@GetMapping(value = "/edit/{id}")
public String edit(@PathVariable Long id, Model model) {
Optional<Order> orderOptional = orderService.findById(id);
if (orderOptional.isPresent()) {
model.addAttribute("order", orderOptional.get());
model.addAttribute("clientIdsList", clientService.getAllClientIds());
model.addAttribute("mechanicIdsList", mechanicService.getAllMechanicIds());
model.addAttribute("orderStatuses", new OrderStatus[] { OrderStatus.SCHEDULED, OrderStatus.DONE, OrderStatus.ACCEPTED });
return "order/edit";
} else {
// TODO: need to show warning
return "redirect:/order";
}
}
@PostMapping(value = "/update/{id}")
public String update(@Valid Order order, BindingResult bindingResult, @PathVariable long id, Model model) {
if (bindingResult.hasErrors()) {
order.setId(id); // why should we do this?
model.addAttribute("clientIdsList", clientService.getAllClientIds());
model.addAttribute("mechanicIdsList", mechanicService.getAllMechanicIds());
model.addAttribute("orderStatuses", new OrderStatus[] { OrderStatus.SCHEDULED, OrderStatus.DONE, OrderStatus.ACCEPTED });
return "order/edit";
}
orderService.save(order);
return "redirect:/order";
}
@PostMapping(value = "/create")
public String save(@Valid Order order, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("clientIdsList", clientService.getAllClientIds());
model.addAttribute("mechanicIdsList", mechanicService.getAllMechanicIds());
model.addAttribute("orderStatuses", new OrderStatus[] { OrderStatus.SCHEDULED, OrderStatus.DONE, OrderStatus.ACCEPTED });
return "order/edit";
}
orderService.save(order);
return "redirect:/order";
}
@DeleteMapping(value = "/delete/{id}")
public ResponseEntity delete(@PathVariable Long id) {
boolean deleteSuccess = orderService.deleteOrderById(id);
if (deleteSuccess) {
return ResponseEntity.ok().build();
} else {
return ResponseEntity.notFound().build();
}
}
}

View File

@ -1,6 +1,8 @@
package com.github.prominence.carrepair.controller.advice;
import com.github.prominence.carrepair.service.CarRepairService;
import com.github.prominence.carrepair.service.ClientService;
import com.github.prominence.carrepair.service.MechanicService;
import com.github.prominence.carrepair.service.OrderService;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
@ -8,16 +10,20 @@ import org.springframework.web.bind.annotation.ModelAttribute;
@ControllerAdvice
public class GlobalInfoAdvice {
private final CarRepairService carRepairService;
private final ClientService clientService;
private final MechanicService mechanicService;
private final OrderService orderService;
public GlobalInfoAdvice(CarRepairService carRepairService) {
this.carRepairService = carRepairService;
public GlobalInfoAdvice(ClientService clientService, MechanicService mechanicService, OrderService orderService) {
this.clientService = clientService;
this.mechanicService = mechanicService;
this.orderService = orderService;
}
@ModelAttribute("globalInfo")
public void addBadgeInfo(Model model) {
model.addAttribute("clientsCount", carRepairService.getClientCount());
model.addAttribute("mechanicsCount", carRepairService.getMechanicCount());
model.addAttribute("ordersCount", carRepairService.getOrderCount());
model.addAttribute("clientsCount", clientService.getClientCount());
model.addAttribute("mechanicsCount", mechanicService.getMechanicCount());
model.addAttribute("ordersCount", orderService.getOrderCount());
}
}

View File

@ -1,22 +1,31 @@
package com.github.prominence.carrepair.demo;
import com.github.javafaker.Faker;
import com.github.prominence.carrepair.enums.OrderStatus;
import com.github.prominence.carrepair.model.Client;
import com.github.prominence.carrepair.model.Mechanic;
import com.github.prominence.carrepair.model.Order;
import com.github.prominence.carrepair.service.ClientService;
import com.github.prominence.carrepair.service.MechanicService;
import com.github.prominence.carrepair.service.OrderService;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Component
public class DemoDataPopulator {
private static final int COUNT = 10;
private static final int COUNT = 100;
private Faker faker = new Faker();
@ -32,9 +41,7 @@ public class DemoDataPopulator {
return client;
}).limit(COUNT).collect(Collectors.toList());
return args -> {
demoClientList.forEach(clientService::save);
};
return args -> demoClientList.forEach(clientService::save);
}
@Bean
@ -49,9 +56,46 @@ public class DemoDataPopulator {
return mechanic;
}).limit(COUNT).collect(Collectors.toList());
return args -> {
demoMechanicList.forEach(mechanicService::save);
};
return args -> demoMechanicList.forEach(mechanicService::save);
}
@Bean
public CommandLineRunner orderDemoData(OrderService orderService, ClientService clientService, MechanicService mechanicService) {
final OrderStatus[] orderStatuses = OrderStatus.values();
long mechanicsCount = mechanicService.getMechanicCount();
long clientsCount = clientService.getClientCount();
List<Order> demoOrderList = Stream.generate(() -> {
Order order = new Order();
order.setOrderStatus(orderStatuses[RandomUtils.nextInt(0, 3)]);
order.setDescription(faker.lorem().characters(10, 1024));
order.setTotalPrice(BigDecimal.valueOf(faker.number().randomDouble(4, 100, 9999)));
order.setCreatedOn(LocalDateTime.ofInstant(faker.date().past(5, TimeUnit.DAYS).toInstant(), ZoneId.systemDefault()));
if (order.getOrderStatus() == OrderStatus.ACCEPTED) {
order.setFinishedOn(LocalDateTime.ofInstant(faker.date().future(10, TimeUnit.DAYS).toInstant(), ZoneId.systemDefault()));
}
final List<Client> clientListSlice = clientService.findAll(getRandomPageable(clientsCount)).getContent();
final Client randomClient = clientListSlice.get(RandomUtils.nextInt(0, clientListSlice.size()));
order.setClient(randomClient);
final List<Mechanic> mechanicListSlise = mechanicService.findAll(getRandomPageable(mechanicsCount)).getContent();
final Mechanic randomMechanic = mechanicListSlise.get(RandomUtils.nextInt(0, mechanicListSlise.size()));
order.setMechanic(randomMechanic);
System.out.println(order); // demo output
return order;
}).limit(COUNT).collect(Collectors.toList());
return args -> demoOrderList.forEach(orderService::save);
}
private Pageable getRandomPageable(long totalRecords) {
final int size = 10;
final int totalPages = (int) (totalRecords / size);
return PageRequest.of(RandomUtils.nextInt(0, totalPages), size);
}
}

View File

@ -0,0 +1,22 @@
package com.github.prominence.carrepair.formatter;
import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
@Component
public class CustomDateTimeFormatter implements Formatter<LocalDateTime> {
@Override
public LocalDateTime parse(String text, Locale locale) throws ParseException {
return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@Override
public String print(LocalDateTime object, Locale locale) {
return object.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
}

View File

@ -0,0 +1,22 @@
package com.github.prominence.carrepair.formatter;
import com.github.prominence.carrepair.enums.OrderStatus;
import org.apache.commons.lang3.StringUtils;
import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.util.Locale;
@Component
public class OrderStatusFormatter implements Formatter<OrderStatus> {
@Override
public OrderStatus parse(String text, Locale locale) throws ParseException {
return OrderStatus.valueOf(text.toUpperCase());
}
@Override
public String print(OrderStatus object, Locale locale) {
return StringUtils.capitalize(object.toString().toLowerCase());
}
}

View File

@ -3,9 +3,12 @@ package com.github.prominence.carrepair.model;
import com.github.prominence.carrepair.enums.OrderStatus;
import javax.persistence.*;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Objects;
@Entity
@Table(name = "orders")
@ -16,13 +19,14 @@ public class Order {
private long id;
@NotNull
@Size(max = 1024)
private String description;
@ManyToOne(fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.EAGER) // change to LAZY after DTO implementation
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@ManyToOne(fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.EAGER) // change to LAZY after DTO implementation
@JoinColumn(name = "mechanic_id", nullable = false)
private Mechanic mechanic;
@ -33,6 +37,7 @@ public class Order {
@Column(name = "finishedOn")
private LocalDateTime finishedOn;
@Min(value = 0)
@Column(name = "totalPrice")
private BigDecimal totalPrice;
@ -116,4 +121,38 @@ public class Order {
public void setOrderStatus(OrderStatus orderStatus) {
this.orderStatus = orderStatus.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Order)) return false;
Order order = (Order) o;
return id == order.id &&
Objects.equals(description, order.description) &&
Objects.equals(client, order.client) &&
Objects.equals(mechanic, order.mechanic) &&
Objects.equals(createdOn, order.createdOn) &&
Objects.equals(finishedOn, order.finishedOn) &&
Objects.equals(totalPrice, order.totalPrice) &&
Objects.equals(orderStatus, order.orderStatus);
}
@Override
public int hashCode() {
return Objects.hash(id, description, client, mechanic, createdOn, finishedOn, totalPrice, orderStatus);
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", description='" + description + '\'' +
", client=" + client +
", mechanic=" + mechanic +
", createdOn=" + createdOn +
", finishedOn=" + finishedOn +
", totalPrice=" + totalPrice +
", orderStatus='" + orderStatus + '\'' +
'}';
}
}

View File

@ -2,9 +2,14 @@ package com.github.prominence.carrepair.repository;
import com.github.prominence.carrepair.model.Client;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ClientRepository extends JpaRepository<Client, Long> {
@Query(value = "select c.id from Client c")
public List<Long> findAllClientIds();
}

View File

@ -2,8 +2,14 @@ package com.github.prominence.carrepair.repository;
import com.github.prominence.carrepair.model.Mechanic;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface MechanicRepository extends JpaRepository<Mechanic, Long> {
@Query(value = "select m.id from Mechanic m")
public List<Long> findAllMechanicIds();
}

View File

@ -1,34 +0,0 @@
package com.github.prominence.carrepair.service;
import com.github.prominence.carrepair.repository.ClientRepository;
import com.github.prominence.carrepair.repository.MechanicRepository;
import com.github.prominence.carrepair.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CarRepairService {
private ClientRepository clientRepository;
private MechanicRepository mechanicRepository;
private OrderRepository orderRepository;
@Autowired
public CarRepairService(ClientRepository clientRepository, MechanicRepository mechanicRepository, OrderRepository orderRepository) {
this.clientRepository = clientRepository;
this.mechanicRepository = mechanicRepository;
this.orderRepository = orderRepository;
}
public long getClientCount() {
return clientRepository.count();
}
public long getMechanicCount() {
return mechanicRepository.count();
}
public long getOrderCount() {
return orderRepository.count();
}
}

View File

@ -6,6 +6,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@ -37,4 +38,12 @@ public class ClientService {
return false;
}
}
public long getClientCount() {
return clientRepository.count();
}
public List<Long> getAllClientIds() {
return clientRepository.findAllClientIds();
}
}

View File

@ -58,4 +58,12 @@ public class MechanicService {
return statistics;
}
public long getMechanicCount() {
return mechanicRepository.count();
}
public List<Long> getAllMechanicIds() {
return mechanicRepository.findAllMechanicIds();
}
}

View File

@ -0,0 +1,44 @@
package com.github.prominence.carrepair.service;
import com.github.prominence.carrepair.model.Order;
import com.github.prominence.carrepair.repository.OrderRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class OrderService {
private OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
public Page<Order> findAll(Pageable pageable) {
return orderRepository.findAll(pageable);
}
public Optional<Order> findById(Long id) {
return orderRepository.findById(id);
}
public Order save(Order client) {
return orderRepository.save(client);
}
public boolean deleteOrderById(Long id) {
try {
orderRepository.deleteById(id);
return true;
} catch (Exception e) {
return false;
}
}
public long getOrderCount() {
return orderRepository.count();
}
}

View File

@ -8,6 +8,7 @@ home.requirements.label = Requirements
client.title = Clients
mechanic.title = Mechanics
order.title = Orders
firstName.label = First Name
middleName.label = Middle Name
@ -16,6 +17,12 @@ phoneNo.label = Phone No
hourlyPayment.label = Hourly Payment
status.label = Status
amount.label = Amount
client.label = Client
mechanic.label = Mechanic
description.label = Description
createdOn.label = Created On
finishedOn.label = Finished On
totalPrice.label = Total Price
showStatistics.button = Statistics

View File

@ -8,6 +8,7 @@ home.requirements.label = Requirements
client.title = Clients
mechanic.title = Mechanics
order.title = Orders
firstName.label = First Name
middleName.label = Middle Name
@ -16,6 +17,12 @@ phoneNo.label = Phone No
hourlyPayment.label = Hourly Payment
status.label = Status
amount.label = Amount
client.label = Client
mechanic.label = Mechanic
description.label = Description
createdOn.label = Created On
finishedOn.label = Finished On
totalPrice.label = Total Price
showStatistics.button = Statistics

View File

@ -8,6 +8,7 @@ home.requirements.label = Требования
client.title = Клиенты
mechanic.title = Механики
order.title = Заказы
firstName.label = Имя
middleName.label = Отчество
@ -16,6 +17,12 @@ phoneNo.label = Номер телефона
hourlyPayment.label = Почасовая оплата
status.label = Статус
amount.label = Количество
client.label = Клиент
mechanic.label = Механик
description.label = Описание
createdOn.label = Дата создания
finishedOn.label = Дата окончания
totalPrice.label = Итоговая цена
showStatistics.button = Статистика

View File

@ -4,3 +4,11 @@ body {
.fieldError {
border: 1px solid red;
}
.word-breakable {
word-break: break-all;
}
.btn-group {
display: flex;
}

View File

@ -16,5 +16,9 @@
<li th:each="err : ${#fields.errors(fieldName)}" th:text="${err}"></li>
</ul>
</div>
<th:block th:fragment="formatDateTime(dateTime)" th:if="${dateTime != null}">
<th:block th:value="${dateTime.format(T(java.time.format.DateTimeFormatter).ofPattern('yyyy-MM-dd HH:mm:ss'))}"/>
</th:block>
</body>
</html>

View File

@ -21,7 +21,7 @@
<ul class="nav navbar-nav">
<li><a th:href="@{/client/}"><th:block th:text="#{badge.clients}"/> <span class="badge" th:text="${clientsCount}"></span></a></li>
<li><a th:href="@{/mechanic/}"><th:block th:text="#{badge.mechanics}"/> <span class="badge" th:text="${mechanicsCount}"></span></a></li>
<li><a href="#"><th:block th:text="#{badge.orders}"/> <span class="badge" th:text="${ordersCount}"></span></a></li>
<li><a th:href="@{/order/}"><th:block th:text="#{badge.orders}"/> <span class="badge" th:text="${ordersCount}"></span></a></li>
</ul>
</div>
</div>

View File

@ -33,7 +33,7 @@
<div class="form-group row">
<label for="mechanicHourlyPayment" class="col-sm-2 col-form-label" th:text="#{hourlyPayment.label}"></label>
<div class="col-sm-10">
<input type="number" name="phoneNo" class="form-control" id="mechanicHourlyPayment" th:field="*{hourlyPayment}" th:errorclass="fieldError" th:value="${mechanic.hourlyPayment}">
<input type="number" name="hourlyPayment" class="form-control" id="mechanicHourlyPayment" th:field="*{hourlyPayment}" th:errorclass="fieldError" th:value="${mechanic.hourlyPayment}">
<div th:replace="common::errors('hourlyPayment')"></div>
</div>
</div>

View File

@ -0,0 +1,77 @@
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{main}">
<head>
<title th:text="#{default.title}"></title>
</head>
<body>
<div layout:fragment="content">
<h1 th:text="#{order.title}"></h1>
<form th:action="'/order/' + ${order.id != null ? 'update/' + order.id : 'create'}" th:object="${order}" method="post">
<div class="form-group row">
<label for="orderDescription" class="col-sm-2 col-form-label" th:text="#{description.label}"></label>
<div class="col-sm-10">
<textarea name="description" class="form-control" id="orderDescription" th:field="*{description}" th:errorclass="fieldError" th:value="${order.description}"></textarea>
<div th:replace="common::errors('description')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderClient" class="col-sm-2 col-form-label" th:text="#{client.label}"></label>
<div class="col-sm-10">
<select name="client.id" class="form-control" id="orderClient" th:field="*{client.id}" th:errorclass="fieldError" th:value="${order.client.id}">
<option th:each="clientId : ${clientIdsList}" th:value="${clientId}" th:text="${clientId}"></option>
</select>
<div th:replace="common::errors('client')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderMechanic" class="col-sm-2 col-form-label" th:text="#{mechanic.label}"></label>
<div class="col-sm-10">
<select name="mechanic.id" class="form-control" id="orderMechanic" th:field="*{mechanic.id}" th:errorclass="fieldError" th:value="${order.mechanic.id}">
<option th:each="mechanicId : ${mechanicIdsList}" th:value="${mechanicId}" th:text="${mechanicId}"></option>
</select>
<div th:replace="common::errors('mechanic')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderCreatedOn" class="col-sm-2 col-form-label" th:text="#{createdOn.label}"></label>
<div class="col-sm-10">
<input type="datetime-local" name="createdOn" class="form-control" id="orderCreatedOn" th:field="*{createdOn}" th:errorclass="fieldError" th:value="${order.createdOn}">
<div th:replace="common::errors('createdOn')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderFinishedOn" class="col-sm-2 col-form-label" th:text="#{finishedOn.label}"></label>
<div class="col-sm-10">
<input type="datetime-local" name="finishedOn" class="form-control" id="orderFinishedOn" th:field="*{finishedOn}" th:errorclass="fieldError" th:value="${order.finishedOn}">
<div th:replace="common::errors('finishedOn')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderTotalPrice" class="col-sm-2 col-form-label" th:text="#{totalPrice.label}"></label>
<div class="col-sm-10">
<input type="number" name="totalPrice" class="form-control" id="orderTotalPrice" th:field="*{totalPrice}" th:errorclass="fieldError" th:value="${order.totalPrice}">
<div th:replace="common::errors('totalPrice')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderStatus" class="col-sm-2 col-form-label" th:text="#{status.label}"></label>
<div class="col-sm-10">
<select name="orderStatus" class="form-control" id="orderStatus" th:field="*{orderStatus}" th:errorclass="fieldError" th:value="${order.orderStatus}">
<option th:each="orderStatus : ${orderStatuses}" th:value="${orderStatus.toString()}" th:text="${{orderStatus}}"></option>
</select>
<div th:replace="common::errors('orderStatus')"></div>
</div>
</div>
<div class="form-group row pull-right">
<div class="col-sm-12">
<a href="/order" class="btn btn-default" th:text="#{common.back.button}"></a>
<button type="submit" class="btn btn-primary" th:text="#{common.save.button}"></button>
</div>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,67 @@
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{main}">
<head>
<title th:text="#{default.title}"></title>
<script th:inline="javascript">
function deleteOrderById(id) {
const confirmationResult = confirm("Are you sure to delete?");
if (confirmationResult) {
const url = /*[[@{/order/delete/}]]*/;
$.ajax({
url: url + id,
type: 'DELETE',
success: function () {
$('#order-row-' + id).remove();
}
});
}
}
</script>
</head>
<body>
<div layout:fragment="content">
<h1 th:text="#{order.title}"></h1>
<div class="pull-right">
<a class="btn btn-success" th:href="@{/order/create}" th:text="#{common.create.button}"></a>
</div>
<table class="table table-striped table-hover">
<thead>
<tr>
<th th:text="#{client.label}"></th>
<th th:text="#{mechanic.label}"></th>
<th th:text="#{description.label}"></th>
<th th:text="#{createdOn.label}"></th>
<th th:text="#{finishedOn.label}"></th>
<th th:text="#{status.label}"></th>
<th th:text="#{totalPrice.label}"></th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
<tr th:each="order : ${orderList}" th:id="'order-row-' + ${order.id}">
<td th:text="${order.client.firstName + ' ' + order.client.lastName + '(' + order.client.id + ')'}"></td>
<td th:text="${order.mechanic.firstName + ' ' + order.mechanic.lastName + '(' + order.mechanic.id + ')'}"></td>
<td class="word-breakable" th:text="${T(org.apache.commons.lang3.StringUtils).abbreviate(order.description, 128)}"></td>
<td th:text="${{order.createdOn}}"></td>
<td th:text="${{order.finishedOn}}"></td>
<td th:text="${{order.orderStatus}}"></td>
<td th:text="${{order.totalPrice}}"></td>
<td style="break-inside: avoid">
<div class="btn-group pull-right">
<a th:href="@{/order/edit/{id}(id=${order.id})}" class="btn btn-default" th:text="#{common.edit.button}"></a>
<button type="button" class="btn btn-danger" th:onclick="'deleteOrderById(' + ${order.id} + ')'" th:text="#{common.delete.button}"></button>
</div>
</td>
</tr>
</tbody>
</table>
<div th:replace="common::pagination(@{/order/}, ${page}, ${totalPages})"></div>
</div>
</body>
</html>