добавил стату по стоимости заказа
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
-- Тестовые клиенты
|
||||
|
||||
INSERT INTO customers (id, name, email, created_at, updated_at)
|
||||
VALUES
|
||||
(1, 'Иван Иванов', 'ivan@mail.ru', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
@@ -7,7 +7,6 @@ VALUES
|
||||
(4, 'Алексей Козлов', 'alex@mail.ru', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
(5, 'Ольга Новикова', 'olga@mail.ru', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
||||
|
||||
-- Тестовые доставки (опционально)
|
||||
INSERT INTO deliveries (id, tracking_number, destination, status, customer_name, created_at, updated_at)
|
||||
VALUES
|
||||
(1, 'IVN777777', 'гоголя 34', 'В пути', 'Иван Иванов', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,7 +4,8 @@ function OrderForm({ customers, deliveries, onSubmit, editOrder }) {
|
||||
const [formData, setFormData] = useState({
|
||||
customerId: '',
|
||||
deliveryId: '',
|
||||
status: 'В пути'
|
||||
status: 'В пути',
|
||||
orderAmount: ''
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -12,17 +13,40 @@ function OrderForm({ customers, deliveries, onSubmit, editOrder }) {
|
||||
setFormData({
|
||||
customerId: editOrder.customer?.id || '',
|
||||
deliveryId: editOrder.delivery?.id || '',
|
||||
status: editOrder.status || 'В пути'
|
||||
status: editOrder.status || 'В пути',
|
||||
orderAmount: editOrder.orderAmount || ''
|
||||
});
|
||||
}
|
||||
}, [editOrder]);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
onSubmit(formData);
|
||||
if (!editOrder) {
|
||||
setFormData({ customerId: '', deliveryId: '', status: 'В пути' });
|
||||
|
||||
|
||||
const submitData = {
|
||||
...formData,
|
||||
customerId: formData.customerId ? parseInt(formData.customerId) : null,
|
||||
deliveryId: formData.deliveryId ? parseInt(formData.deliveryId) : null,
|
||||
orderAmount: parseFloat(formData.orderAmount) || 0
|
||||
};
|
||||
|
||||
|
||||
if (!submitData.customerId || !submitData.deliveryId) {
|
||||
alert("Пожалуйста, выберите клиента и доставку!");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Отправляемые данные:", submitData);
|
||||
onSubmit(submitData);
|
||||
|
||||
if (!editOrder) {
|
||||
setFormData({ customerId: '', deliveryId: '', status: 'В пути', orderAmount: '' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData(prev => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const statusOptions = ['В пути', 'Доставлено', 'Обработка', 'Отменен'];
|
||||
@@ -34,8 +58,9 @@ function OrderForm({ customers, deliveries, onSubmit, editOrder }) {
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<label>Клиент: </label>
|
||||
<select
|
||||
name="customerId"
|
||||
value={formData.customerId}
|
||||
onChange={(e) => setFormData({...formData, customerId: e.target.value})}
|
||||
onChange={handleChange}
|
||||
required
|
||||
>
|
||||
<option value="">Выберите клиента</option>
|
||||
@@ -50,8 +75,9 @@ function OrderForm({ customers, deliveries, onSubmit, editOrder }) {
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<label>Доставка: </label>
|
||||
<select
|
||||
name="deliveryId"
|
||||
value={formData.deliveryId}
|
||||
onChange={(e) => setFormData({...formData, deliveryId: e.target.value})}
|
||||
onChange={handleChange}
|
||||
required
|
||||
>
|
||||
<option value="">Выберите доставку</option>
|
||||
@@ -66,8 +92,9 @@ function OrderForm({ customers, deliveries, onSubmit, editOrder }) {
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<label>Статус: </label>
|
||||
<select
|
||||
name="status"
|
||||
value={formData.status}
|
||||
onChange={(e) => setFormData({...formData, status: e.target.value})}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{statusOptions.map(status => (
|
||||
<option key={status} value={status}>{status}</option>
|
||||
@@ -75,6 +102,21 @@ function OrderForm({ customers, deliveries, onSubmit, editOrder }) {
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<label>Стоимость заказа (руб): </label>
|
||||
<input
|
||||
type="number"
|
||||
name="orderAmount"
|
||||
value={formData.orderAmount}
|
||||
onChange={handleChange}
|
||||
placeholder="Введите сумму"
|
||||
min="0"
|
||||
step="0.01"
|
||||
required
|
||||
style={{ marginLeft: '10px', padding: '5px' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button type="submit" style={{ padding: '10px 20px' }}>
|
||||
{editOrder ? 'Обновить заказ' : 'Создать заказ'}
|
||||
</button>
|
||||
|
||||
@@ -6,21 +6,31 @@ function OrderItem({ order, onEdit, onDelete }) {
|
||||
margin: '10px 0',
|
||||
borderRadius: '5px'
|
||||
}}>
|
||||
<h4>Заказ #{order.id}</h4>
|
||||
<h3>Заказ #{order.id}</h3>
|
||||
|
||||
<p><strong>Клиент:</strong> {order.customer?.name} ({order.customer?.email})</p>
|
||||
|
||||
<p><strong>Доставка:</strong> {order.delivery?.trackingNumber} - {order.delivery?.destination}</p>
|
||||
<p><strong>Статус:</strong>
|
||||
<span style={{
|
||||
color: order.status === 'Доставлено' ? 'green' :
|
||||
order.status === 'В пути' ? 'orange' : 'gray',
|
||||
fontWeight: 'bold',
|
||||
marginLeft: '10px'
|
||||
}}>
|
||||
{order.status}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p><strong>Статус:</strong> {order.status}</p>
|
||||
|
||||
{}
|
||||
<p><strong>Сумма заказа:</strong> {order.orderAmount ? `${order.orderAmount} руб.` : 'Не указана'}</p>
|
||||
|
||||
<div style={{ marginTop: '10px' }}>
|
||||
<button
|
||||
onClick={() => onEdit(order)}
|
||||
style={{ marginRight: '10px', padding: '5px 10px' }}
|
||||
>
|
||||
Редактировать
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onDelete(order.id)}
|
||||
style={{ padding: '5px 10px', backgroundColor: '#ff4444', color: 'white' }}
|
||||
>
|
||||
Удалить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,11 +62,11 @@ function OrderList() {
|
||||
|
||||
const handleCreateOrder = async (orderData) => {
|
||||
try {
|
||||
|
||||
const orderRq = {
|
||||
customerId: orderData.customerId,
|
||||
deliveryId: orderData.deliveryId,
|
||||
status: orderData.status
|
||||
status: orderData.status,
|
||||
orderAmount: orderData.orderAmount
|
||||
};
|
||||
|
||||
const response = await fetch('http://localhost:8080/api/orders', {
|
||||
@@ -96,7 +96,8 @@ function OrderList() {
|
||||
const orderRq = {
|
||||
customerId: orderData.customerId,
|
||||
deliveryId: orderData.deliveryId,
|
||||
status: orderData.status
|
||||
status: orderData.status,
|
||||
orderAmount: orderData.orderAmount
|
||||
};
|
||||
|
||||
const response = await fetch(`http://localhost:8080/api/orders/${editingOrder.id}`, {
|
||||
|
||||
@@ -9,8 +9,9 @@ import jakarta.validation.Valid;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Map;
|
||||
|
||||
@CrossOrigin(origins = "http://localhost:5173")
|
||||
@RestController
|
||||
@@ -33,44 +34,23 @@ public class OrderController {
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "Получить заказ по ID")
|
||||
public ResponseEntity<OrderRs> getOne(@PathVariable Long id) {
|
||||
Optional<OrderRs> order = orderService.findById(id);
|
||||
return order.map(ResponseEntity::ok)
|
||||
return orderService.findById(id)
|
||||
.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@GetMapping("/customer/{customerId}")
|
||||
@Operation(summary = "Получить заказы по ID клиента")
|
||||
public List<OrderRs> getByCustomer(@PathVariable Long customerId) {
|
||||
return orderService.findByCustomerId(customerId);
|
||||
}
|
||||
|
||||
@GetMapping("/status/{status}")
|
||||
@Operation(summary = "Получить заказы по статусу")
|
||||
public List<OrderRs> getByStatus(@PathVariable String status) {
|
||||
return orderService.findByStatus(status);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "Создать новый заказ")
|
||||
public ResponseEntity<?> create(@Valid @RequestBody OrderRq orderRq) {
|
||||
try {
|
||||
OrderRs created = orderService.create(orderRq);
|
||||
return ResponseEntity.ok(created);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
public OrderRs create(@Valid @RequestBody OrderRq orderRq) {
|
||||
return orderService.create(orderRq);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "Обновить заказ")
|
||||
public ResponseEntity<?> update(@PathVariable Long id, @Valid @RequestBody OrderRq orderRq) {
|
||||
try {
|
||||
Optional<OrderRs> updated = orderService.update(id, orderRq);
|
||||
return updated.map(ResponseEntity::ok)
|
||||
@Operation(summary = "Обновить данные заказа")
|
||||
public ResponseEntity<OrderRs> update(@PathVariable Long id, @Valid @RequestBody OrderRq orderRq) {
|
||||
return orderService.update(id, orderRq)
|
||||
.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@@ -80,8 +60,26 @@ public class OrderController {
|
||||
return deleted ? ResponseEntity.ok().build() : ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@GetMapping("/stats/customer-spending")
|
||||
@Operation(summary = "Получить статистику трат клиентов")
|
||||
public List<OrderService.CustomerSpendingStats> getCustomerSpendingStats() {
|
||||
return orderService.getCustomerSpendingStats();
|
||||
}
|
||||
|
||||
@GetMapping("/stats/total-revenue")
|
||||
@Operation(summary = "Получить общую выручку")
|
||||
public Map<String, BigDecimal> getTotalRevenue() {
|
||||
return Map.of("totalRevenue", orderService.getTotalRevenue());
|
||||
}
|
||||
|
||||
@GetMapping("/stats/average-order-value")
|
||||
@Operation(summary = "Получить средний чек")
|
||||
public Map<String, BigDecimal> getAverageOrderValue() {
|
||||
return orderService.getAverageOrderValue();
|
||||
}
|
||||
|
||||
@GetMapping("/stats/monthly")
|
||||
@Operation(summary = "Получить месячную статистику заказов")
|
||||
@Operation(summary = "Получить статистику заказов по месяцам")
|
||||
public List<OrderService.OrderMonthlyStats> getOrderMonthlyStats() {
|
||||
return orderService.getOrderMonthlyStats();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.example.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class OrderRq {
|
||||
@NotNull(message = "ID клиента обязателен")
|
||||
@@ -12,16 +13,18 @@ public class OrderRq {
|
||||
@NotNull(message = "Статус обязателен")
|
||||
private String status;
|
||||
|
||||
@NotNull(message = "Стоимость заказа обязательна")
|
||||
private BigDecimal orderAmount;
|
||||
|
||||
public OrderRq() {}
|
||||
|
||||
public OrderRq(Long customerId, Long deliveryId, String status) {
|
||||
public OrderRq(Long customerId, Long deliveryId, String status, BigDecimal orderAmount) {
|
||||
this.customerId = customerId;
|
||||
this.deliveryId = deliveryId;
|
||||
this.status = status;
|
||||
this.orderAmount = orderAmount;
|
||||
}
|
||||
|
||||
|
||||
public Long getCustomerId() { return customerId; }
|
||||
public void setCustomerId(Long customerId) { this.customerId = customerId; }
|
||||
|
||||
@@ -30,4 +33,7 @@ public class OrderRq {
|
||||
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
|
||||
public BigDecimal getOrderAmount() { return orderAmount; }
|
||||
public void setOrderAmount(BigDecimal orderAmount) { this.orderAmount = orderAmount; }
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.example.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class OrderRs {
|
||||
@@ -7,10 +8,10 @@ public class OrderRs {
|
||||
private CustomerRs customer;
|
||||
private DeliveryRs delivery;
|
||||
private String status;
|
||||
private BigDecimal orderAmount;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
@@ -23,6 +24,9 @@ public class OrderRs {
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
|
||||
public BigDecimal getOrderAmount() { return orderAmount; }
|
||||
public void setOrderAmount(BigDecimal orderAmount) { this.orderAmount = orderAmount; }
|
||||
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
package com.example.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "orders")
|
||||
public class Order extends BaseEntity {
|
||||
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "customer_id", nullable = false)
|
||||
private Customer customer;
|
||||
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "delivery_id", nullable = false)
|
||||
private Delivery delivery;
|
||||
@@ -19,70 +18,37 @@ public class Order extends BaseEntity {
|
||||
@Column(name = "status", nullable = false)
|
||||
private String status;
|
||||
|
||||
@Column(name = "order_amount", nullable = false)
|
||||
private BigDecimal orderAmount;
|
||||
|
||||
public Order() {}
|
||||
|
||||
public Order(Customer customer, Delivery delivery, String status) {
|
||||
public Order(Customer customer, Delivery delivery, String status, BigDecimal orderAmount) {
|
||||
this.customer = customer;
|
||||
this.delivery = delivery;
|
||||
this.status = status;
|
||||
this.orderAmount = orderAmount;
|
||||
}
|
||||
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public Customer getCustomer() { return customer; }
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
|
||||
if (customer != null && !customer.getOrders().contains(this)) {
|
||||
customer.getOrders().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Delivery getDelivery() {
|
||||
return delivery;
|
||||
}
|
||||
|
||||
public Delivery getDelivery() { return delivery; }
|
||||
public void setDelivery(Delivery delivery) {
|
||||
this.delivery = delivery;
|
||||
|
||||
if (delivery != null && !delivery.getOrders().contains(this)) {
|
||||
delivery.getOrders().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Order{" +
|
||||
"id=" + getId() +
|
||||
", customer=" + (customer != null ? customer.getName() : "null") +
|
||||
", delivery=" + (delivery != null ? delivery.getTrackingNumber() : "null") +
|
||||
", status='" + status + '\'' +
|
||||
", createdAt=" + getCreatedAt() +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof Order)) return false;
|
||||
Order order = (Order) o;
|
||||
return getId() != null && getId().equals(order.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
public BigDecimal getOrderAmount() { return orderAmount; }
|
||||
public void setOrderAmount(BigDecimal orderAmount) { this.orderAmount = orderAmount; }
|
||||
}
|
||||
@@ -13,6 +13,7 @@ public class OrderMapper {
|
||||
public Order toEntity(OrderRq orderRq) {
|
||||
Order order = new Order();
|
||||
order.setStatus(orderRq.getStatus());
|
||||
order.setOrderAmount(orderRq.getOrderAmount());
|
||||
return order;
|
||||
}
|
||||
|
||||
@@ -20,10 +21,10 @@ public class OrderMapper {
|
||||
OrderRs orderRs = new OrderRs();
|
||||
orderRs.setId(order.getId());
|
||||
orderRs.setStatus(order.getStatus());
|
||||
orderRs.setOrderAmount(order.getOrderAmount());
|
||||
orderRs.setCreatedAt(order.getCreatedAt());
|
||||
orderRs.setUpdatedAt(order.getUpdatedAt());
|
||||
|
||||
|
||||
if (order.getCustomer() != null) {
|
||||
CustomerRs customerRs = new CustomerRs();
|
||||
customerRs.setId(order.getCustomer().getId());
|
||||
|
||||
@@ -3,47 +3,36 @@ package com.example.repository;
|
||||
import com.example.entity.Order;
|
||||
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 java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface OrderRepository extends JpaRepository<Order, Long> {
|
||||
|
||||
List<Order> findByCustomerId(Long customerId);
|
||||
|
||||
List<Order> findByDeliveryId(Long deliveryId);
|
||||
|
||||
List<Order> findByStatus(String status);
|
||||
|
||||
|
||||
@Query("SELECT MONTH(o.createdAt) as month, " +
|
||||
"COUNT(o.id) as orderCount " +
|
||||
"FROM Order o " +
|
||||
"GROUP BY MONTH(o.createdAt) " +
|
||||
"ORDER BY month")
|
||||
List<OrderMonthlyStats> findOrderMonthlyStats();
|
||||
|
||||
interface OrderMonthlyStats {
|
||||
Integer getMonth();
|
||||
Long getOrderCount();
|
||||
}
|
||||
@Query("SELECT o.status, COUNT(o) FROM Order o GROUP BY o.status")
|
||||
List<Object[]> findOrderStatusStats();
|
||||
|
||||
|
||||
@Query("SELECT o.status as status, " +
|
||||
"COUNT(o.id) as total " +
|
||||
"FROM Order o " +
|
||||
"GROUP BY o.status")
|
||||
List<OrderStatusStats> findOrderStatusStats();
|
||||
@Query("SELECT MONTH(o.createdAt), COUNT(o) FROM Order o GROUP BY MONTH(o.createdAt)")
|
||||
List<Object[]> findOrderMonthlyStats();
|
||||
|
||||
interface OrderStatusStats {
|
||||
String getStatus();
|
||||
Long getTotal();
|
||||
}
|
||||
|
||||
@Query("SELECT o.customer.id, o.customer.name, SUM(o.orderAmount), COUNT(o) " +
|
||||
"FROM Order o GROUP BY o.customer.id, o.customer.name ORDER BY SUM(o.orderAmount) DESC")
|
||||
List<Object[]> findCustomerSpendingStats();
|
||||
|
||||
|
||||
@Query("SELECT SUM(o.orderAmount) FROM Order o")
|
||||
BigDecimal getTotalRevenue();
|
||||
|
||||
|
||||
@Query("SELECT o FROM Order o WHERE o.customer.id = :customerId AND o.status = :status")
|
||||
List<Order> findCustomerOrdersByStatus(@Param("customerId") Long customerId,
|
||||
@Param("status") String status);
|
||||
List<Order> findCustomerOrdersByStatus(Long customerId, String status);
|
||||
}
|
||||
@@ -12,7 +12,10 @@ import com.example.repository.OrderRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@@ -95,6 +98,7 @@ public class OrderService {
|
||||
order.setCustomer(customer);
|
||||
order.setDelivery(delivery);
|
||||
order.setStatus(orderRq.getStatus());
|
||||
order.setOrderAmount(orderRq.getOrderAmount());
|
||||
|
||||
Order updated = orderRepository.save(order);
|
||||
return orderMapper.toResponse(updated);
|
||||
@@ -109,31 +113,116 @@ public class OrderService {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<OrderMonthlyStats> getOrderMonthlyStats() {
|
||||
List<OrderRepository.OrderMonthlyStats> repoStats = orderRepository.findOrderMonthlyStats();
|
||||
|
||||
return repoStats.stream()
|
||||
.map(stat -> new OrderMonthlyStats(stat.getMonth(), stat.getOrderCount()))
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<CustomerSpendingStats> getCustomerSpendingStats() {
|
||||
List<Order> allOrders = orderRepository.findAll();
|
||||
|
||||
|
||||
Map<Customer, List<Order>> ordersByCustomer = allOrders.stream()
|
||||
.collect(java.util.stream.Collectors.groupingBy(Order::getCustomer));
|
||||
|
||||
return ordersByCustomer.entrySet().stream()
|
||||
.map(entry -> {
|
||||
Customer customer = entry.getKey();
|
||||
List<Order> customerOrders = entry.getValue();
|
||||
|
||||
BigDecimal totalSpent = customerOrders.stream()
|
||||
.map(Order::getOrderAmount)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
return new CustomerSpendingStats(
|
||||
customer.getId(),
|
||||
customer.getName(),
|
||||
totalSpent,
|
||||
(long) customerOrders.size()
|
||||
);
|
||||
})
|
||||
.sorted((a, b) -> b.totalSpent().compareTo(a.totalSpent()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public record OrderMonthlyStats(Integer month, Long orderCount) {}
|
||||
public record CustomerSpendingStats(Long customerId, String customerName, BigDecimal totalSpent, Long orderCount) {}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<OrderStatusStats> getOrderStatusStats() {
|
||||
List<OrderRepository.OrderStatusStats> repoStats = orderRepository.findOrderStatusStats();
|
||||
List<Order> allOrders = orderRepository.findAll();
|
||||
|
||||
return repoStats.stream()
|
||||
.map(stat -> new OrderStatusStats(stat.getStatus(), stat.getTotal()))
|
||||
|
||||
Map<String, List<Order>> ordersByStatus = allOrders.stream()
|
||||
.collect(java.util.stream.Collectors.groupingBy(Order::getStatus));
|
||||
|
||||
return ordersByStatus.entrySet().stream()
|
||||
.map(entry -> new OrderStatusStats(
|
||||
entry.getKey(),
|
||||
(long) entry.getValue().size()
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public record OrderStatusStats(String status, Long total) {}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Order> getCustomerOrdersByStatus(Long customerId, String status) {
|
||||
return orderRepository.findCustomerOrdersByStatus(customerId, status);
|
||||
public List<OrderMonthlyStats> getOrderMonthlyStats() {
|
||||
List<Order> allOrders = orderRepository.findAll();
|
||||
|
||||
|
||||
Map<Integer, List<Order>> ordersByMonth = allOrders.stream()
|
||||
.collect(java.util.stream.Collectors.groupingBy(order ->
|
||||
order.getCreatedAt().getMonthValue()
|
||||
));
|
||||
|
||||
return ordersByMonth.entrySet().stream()
|
||||
.map(entry -> new OrderMonthlyStats(
|
||||
entry.getKey(),
|
||||
(long) entry.getValue().size()
|
||||
))
|
||||
.sorted((a, b) -> a.month().compareTo(b.month()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public record OrderMonthlyStats(Integer month, Long orderCount) {}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getTotalRevenue() {
|
||||
List<Order> allOrders = orderRepository.findAll();
|
||||
return allOrders.stream()
|
||||
.map(Order::getOrderAmount)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Map<String, BigDecimal> getAverageOrderValue() {
|
||||
List<Order> allOrders = orderRepository.findAll();
|
||||
|
||||
if (allOrders.isEmpty()) {
|
||||
return Map.of("averageOrderValue", BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
BigDecimal totalRevenue = getTotalRevenue();
|
||||
BigDecimal average = totalRevenue.divide(BigDecimal.valueOf(allOrders.size()), 2, RoundingMode.HALF_UP);
|
||||
|
||||
return Map.of("averageOrderValue", average);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Map<String, Object> getBusinessSummary() {
|
||||
long totalCustomers = customerRepository.count();
|
||||
long totalDeliveries = deliveryRepository.count();
|
||||
long totalOrders = orderRepository.count();
|
||||
BigDecimal totalRevenue = getTotalRevenue();
|
||||
|
||||
List<Order> activeOrders = orderRepository.findByStatus("В пути");
|
||||
long activeOrdersCount = activeOrders.size();
|
||||
|
||||
return Map.of(
|
||||
"totalCustomers", totalCustomers,
|
||||
"totalDeliveries", totalDeliveries,
|
||||
"totalOrders", totalOrders,
|
||||
"totalRevenue", totalRevenue,
|
||||
"activeOrders", activeOrdersCount
|
||||
);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Тестовые клиенты
|
||||
|
||||
INSERT INTO customers (id, name, email, created_at, updated_at)
|
||||
VALUES
|
||||
(1, 'Иван Иванов', 'ivan@mail.ru', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
@@ -7,7 +7,6 @@ VALUES
|
||||
(4, 'Алексей Козлов', 'alex@mail.ru', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
(5, 'Ольга Новикова', 'olga@mail.ru', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
||||
|
||||
-- Тестовые доставки (опционально)
|
||||
INSERT INTO deliveries (id, tracking_number, destination, status, customer_name, created_at, updated_at)
|
||||
VALUES
|
||||
(1, 'IVN777777', 'гоголя 34', 'В пути', 'Иван Иванов', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
|
||||
Reference in New Issue
Block a user