Skip to content

Commit

Permalink
Supprimer ou implementer le bouton "publier la vente" #32
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminpochat committed Sep 29, 2024
1 parent ca58f35 commit 627ec68
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 51 deletions.
4 changes: 0 additions & 4 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
Fonction mettre en vente

Frontend : dans le formulaire de création d'une vente, indiquer dans le titre des steps les données saisies (notamment la production sélectionnée)

Fonction publier la vente

Backend : modèlen : ajouter un attrbut pour indiquer si une vente est publiée ou notamment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public ResponseEntity<List<Sale>> getSales(String privateAccessKey) {
} else {
saleRepository.findByPrivateAccessKeyIgnoreCase(privateAccessKey).forEach(sales::add);
}
return new ResponseEntity<>(sales, OK);
List publishedSales = sales.stream().filter(sale -> sale.getPublishedToCustomers() != null && sale.getPublishedToCustomers()).toList();
return new ResponseEntity<>(publishedSales, OK);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
Expand Down Expand Up @@ -42,6 +41,7 @@ public class ProducerService implements ProducersApiDelegate {

@Autowired
ProducerPublicDataService producerPublicDataService;

@Autowired
private ProductionRepository productionRepository;

Expand All @@ -52,6 +52,7 @@ public ResponseEntity<Sale> createProducerSale(Integer producerId, Sale sale) {
return new ResponseEntity<>(FORBIDDEN);
}
sale.setSeller(producer);
sale.setPublishedToCustomers(true);
return new ResponseEntity<>(saleRepository.save(sale), CREATED);
}

Expand Down Expand Up @@ -168,6 +169,18 @@ public ResponseEntity<Sale> addProductionToSale(Integer producerId, Integer sale
return new ResponseEntity<>(sale, OK);
}

@Override
public ResponseEntity<Void> setSalePublishedToCustomers(Integer producerId, Integer saleId, Boolean publishedToCustomers) {
Producer producer = authenticationService.getAuthenticatedProducer();
if (!producer.getId().equals(producerId)) {
return new ResponseEntity<>(FORBIDDEN);
}
Sale sale = saleRepository.findById(saleId).orElseThrow();
sale.setPublishedToCustomers(publishedToCustomers);
saleRepository.save(sale);
return new ResponseEntity<>(NO_CONTENT);
}

Producer getRandomProducer(long producerCount, Iterator<Producer> producersIterator) {
long randomProducerIndex = (long) (getRandom() * producerCount);
if(!producersIterator.hasNext()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,14 @@ databaseChangeLog:
- column:
name: private_access_key
type: VARCHAR(255)

- changeSet:
id: viandeendirect-2024-09-28
author: benjamin
changes:
- addColumn:
tableName: sales
columns:
- column:
name: published_to_customers
type: BOOLEAN
28 changes: 26 additions & 2 deletions backend/model/src/main/java/eu/viandeendirect/model/Sale.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ public class Sale {
@JsonProperty("privateAccessKey")
private String privateAccessKey;

@JsonProperty("publishedToCustomers")
private Boolean publishedToCustomers;

public Sale id(Integer id) {
this.id = id;
return this;
Expand Down Expand Up @@ -318,6 +321,25 @@ public void setPrivateAccessKey(String privateAccessKey) {
this.privateAccessKey = privateAccessKey;
}

public Sale publishedToCustomers(Boolean publishedToCustomers) {
this.publishedToCustomers = publishedToCustomers;
return this;
}

/**
* if false, the sale is not visible by customer
* @return publishedToCustomers
*/

@Schema(name = "publishedToCustomers", description = "if false, the sale is not visible by customer", required = false)
public Boolean getPublishedToCustomers() {
return publishedToCustomers;
}

public void setPublishedToCustomers(Boolean publishedToCustomers) {
this.publishedToCustomers = publishedToCustomers;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand All @@ -338,12 +360,13 @@ public boolean equals(Object o) {
Objects.equals(this.deliveryAddressLine2, sale.deliveryAddressLine2) &&
Objects.equals(this.deliveryCity, sale.deliveryCity) &&
Objects.equals(this.deliveryZipCode, sale.deliveryZipCode) &&
Objects.equals(this.privateAccessKey, sale.privateAccessKey);
Objects.equals(this.privateAccessKey, sale.privateAccessKey) &&
Objects.equals(this.publishedToCustomers, sale.publishedToCustomers);
}

@Override
public int hashCode() {
return Objects.hash(id, seller, productions, orders, deliveryStart, deliveryStop, deliveryAddressName, deliveryAddressLine1, deliveryAddressLine2, deliveryCity, deliveryZipCode, privateAccessKey);
return Objects.hash(id, seller, productions, orders, deliveryStart, deliveryStop, deliveryAddressName, deliveryAddressLine1, deliveryAddressLine2, deliveryCity, deliveryZipCode, privateAccessKey, publishedToCustomers);
}

@Override
Expand All @@ -362,6 +385,7 @@ public String toString() {
sb.append(" deliveryCity: ").append(toIndentedString(deliveryCity)).append("\n");
sb.append(" deliveryZipCode: ").append(toIndentedString(deliveryZipCode)).append("\n");
sb.append(" privateAccessKey: ").append(toIndentedString(privateAccessKey)).append("\n");
sb.append(" publishedToCustomers: ").append(toIndentedString(publishedToCustomers)).append("\n");
sb.append("}");
return sb.toString();
}
Expand Down
4 changes: 4 additions & 0 deletions frontend/app/src/api/mock/MockApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ export class MockApi {
this.log('addProductionToSale', args)
}

setSalePublishedToCustomers(args) {
this.log('setSalePublishedToCustomers', args)
}

getProducerSales(args) {
this.log('getProducerSales', args)
return this.mockApiProducers.getProducerSales()
Expand Down
4 changes: 4 additions & 0 deletions frontend/app/src/api/mock/MockApiProducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export class MockApiProducers {
deliveryAddressLine2: undefined,
deliveryCity: 'Rémilly',
deliveryZipCode: '57580',
publishedToCustomers: true,
productions: [
{
id: 1,
Expand Down Expand Up @@ -128,6 +129,7 @@ export class MockApiProducers {
deliveryAddressLine2: 'Derrière l\'Arc de Triomphe',
deliveryCity: 'Paris',
deliveryZipCode: '75000',
publishedToCustomers: false,
productions: [
{
id: 2,
Expand Down Expand Up @@ -203,6 +205,8 @@ export class MockApiProducers {
deliveryAddressLine2: 'Derrière l\'Arc de Triomphe',
deliveryCity: 'Paris',
deliveryZipCode: '75000',
privateAccessKey: 'm0td3p4zz',
publishedToCustomers: true,
productions: [
{
id: 3,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ export default function VisitFarmButton({producer}) {
onClose={() => setSlideShowDisplayed(false)}>
<iframe
src={producer.slideShowUrl}
allowfullscreen="true"
mozallowfullscreen="true"
webkitallowfullscreen="true"
allowFullScreen={true}
width="100%"
height="100%"/>
<DialogActions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { ProducerService } from "../../../commons/service/ProducerService.ts";
import { Producer } from "@viandeendirect/api/dist/models/Producer.ts";
import { BeefProduction } from "@viandeendirect/api/dist/models/BeefProduction.ts";
import { Sale } from "@viandeendirect/api/dist/models/Sale.ts";
import { Box, Button, ButtonGroup, FormControl, InputLabel, MenuItem, Select, Snackbar, Stack, Switch, Typography } from "@mui/material";
import { Button, ButtonGroup, FormControl, InputLabel, MenuItem, Select, Snackbar, Stack, Switch, Typography } from "@mui/material";
import { AnimalTypeUtils } from "../../../../enum/AnimalTypeUtils.ts";
import dayjs from "dayjs";
import { useLoaderData, useNavigate } from "react-router-dom";
import { useKeycloak } from "@react-keycloak/web";
import { useSnackbar } from '../../../commons/components/SnackbarProvider.tsx'

export default function PublicationBeefProductionToSale(){

Expand Down Expand Up @@ -87,7 +89,7 @@ export default function PublicationBeefProductionToSale(){
console.log(`publish to sale ${selectedSale?.id}`)
navigate(-1)
} catch (error) {
showSnackbar(`Une erreur s'est produite`, 'error');
showSnackbar(`Oops... une erreur s'est produite`, 'error');
}

}
Expand Down
76 changes: 58 additions & 18 deletions frontend/app/src/domains/sale/components/SaleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,38 @@ import React, { useEffect, useState } from 'react'

import { Button, ButtonGroup, Card, CardActions, CardContent, CardHeader, Chip, Typography, Stack } from "@mui/material"
import LockIcon from '@mui/icons-material/Lock';
import VisibilityIcon from '@mui/icons-material/Visibility';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import dayjs from 'dayjs'
import SaleCardBeefProduction from './SaleCardBeefProduction.tsx';
import { useKeycloak } from '@react-keycloak/web';
import { useNavigate } from 'react-router-dom';
import { ApiBuilder } from '../../../api/ApiBuilder.ts';
import { Order } from '@viandeendirect/api/dist/models/Order'
import { Production } from '@viandeendirect/api/dist/models/Production'
import { ProducerService } from '../../commons/service/ProducerService.ts';
import { useSnackbar } from '../../commons/components/SnackbarProvider.tsx'
import { Sale } from '@viandeendirect/api/dist/models/Sale';


export default function SaleCard({sale: sale}) {

const [orders, setOrders] = useState<Array<Order>>([])
const [productions, setProductions] = useState<Array<Production>>([])
const {keycloak} = useKeycloak()
const navigate = useNavigate()
const apiBuilder = new ApiBuilder()
const showSnackbar = useSnackbar()

const [orders, setOrders] = useState<Array<Order>>([])
const [productions, setProductions] = useState<Array<Production>>([])
const [currentSale, setCurrentSale] = useState<Sale>(sale)


useEffect(() => {
const loadData = async () => {
const api = await apiBuilder.getAuthenticatedApi(keycloak)
const loadedOrders = await api.getSaleOrders({saleId: sale.id})
const loadedOrders = await api.getSaleOrders({saleId: currentSale.id})
setOrders(loadedOrders)
const loadedProductions = await api.getSaleProductions({saleId: sale.id})
const loadedProductions = await api.getSaleProductions({saleId: currentSale.id})
setProductions(loadedProductions)
}
loadData()
Expand All @@ -35,11 +43,11 @@ export default function SaleCard({sale: sale}) {
<Card>
<CardHeader
title={<Stack alignItems="center" direction="row" gap={2} justifyContent='space-between'>
<div>{`Vente du ${dayjs(sale.deliveryStart).format('DD/MM/YYYY')}`}</div>
{getPrivateAccessKeyChip()}
<div>{`Vente du ${dayjs(currentSale.deliveryStart).format('DD/MM/YYYY')}`}</div>
{getChips()}
</Stack>
}
subheader={sale.deliveryAddressName}>
subheader={currentSale.deliveryAddressName}>
</CardHeader>
<CardContent>
<div className='sale-card-line-1'>
Expand All @@ -48,10 +56,10 @@ export default function SaleCard({sale: sale}) {
Livraison
</Typography>
<Typography>
<div>{sale.deliveryAddressLine1}</div>
<div>{sale.deliveryAddressLine2}</div>
<div>{sale.deliveryZipCode} - {sale.deliveryCity}</div>
<div>entre {dayjs(sale.deliveryStart).format('HH:mm')} et {dayjs(sale.deliveryStop).format('HH:mm')}</div>
<div>{currentSale.deliveryAddressLine1}</div>
<div>{currentSale.deliveryAddressLine2}</div>
<div>{currentSale.deliveryZipCode} - {currentSale.deliveryCity}</div>
<div>entre {dayjs(currentSale.deliveryStart).format('HH:mm')} et {dayjs(currentSale.deliveryStop).format('HH:mm')}</div>
</Typography>
</div>
<div>
Expand Down Expand Up @@ -80,8 +88,8 @@ export default function SaleCard({sale: sale}) {
</CardContent>
<CardActions>
<ButtonGroup>
<Button size="small">Publier la vente</Button>
<Button size="small" onClick={() => navigate(`/sale/${sale.id}/orders`)}>Gérer les commandes</Button>
{getPublicationButton()}
<Button size="small" onClick={() => navigate(`/sale/${currentSale.id}/orders`)}>Gérer les commandes</Button>
<Button size="small">Préparer la livraison</Button>
</ButtonGroup>
</CardActions>
Expand All @@ -94,7 +102,6 @@ export default function SaleCard({sale: sale}) {
return <SaleCardBeefProduction key={`beef-production-card-${production.id}`} production={production}/>
default:
return <></>

}
}

Expand All @@ -112,10 +119,43 @@ export default function SaleCard({sale: sale}) {
.reduce((totalAmout, orderItemAmout) => totalAmout + orderItemAmout, 0)
}

function getPrivateAccessKeyChip() {
if (sale.privateAccessKey) {
return <Chip icon={<LockIcon/>} size='small' color='warning' label={`code accès privé : ${sale.privateAccessKey}`}/>
function getChips() {
let publishStatutChip = <></>
if (currentSale.publishedToCustomers) {
publishStatutChip = <Chip icon={<VisibilityIcon/>} size='small' color='success' label="publié"/>
} else {
publishStatutChip = <Chip icon={<VisibilityOffIcon/>} size='small' color='warning' label='non publié'/>
}
let privateAccessChip = <></>
if (currentSale.privateAccessKey) {
privateAccessChip = <Chip icon={<LockIcon/>} size='small' color='warning' label={(`${currentSale.privateAccessKey}`)}/>
}
return <Stack direction='column' alignItems='flex-end' gap='0.2rem'>{publishStatutChip}{privateAccessChip}</Stack>
}

function getPublicationButton(): React.ReactNode {
if (currentSale.publishedToCustomers) {
return <Button size="small" onClick={() => setPublishedToCustomers(false)}>Retirer la vente</Button>
}
return <Button size="small" onClick={() => setPublishedToCustomers(true)}>Publier la vente</Button>
}



async function setPublishedToCustomers(published: boolean): Promise<void> {
const producerService = new ProducerService(keycloak)
const producer = await producerService.loadProducer()
const api = await apiBuilder.getAuthenticatedApi(keycloak)
try {
await api.setSalePublishedToCustomers({saleId: currentSale.id, producerId: +producer.id, publishedToCustomers: published})
setCurrentSale({...currentSale, publishedToCustomers: published})
if (published) {
showSnackbar(`La vente livrée le ${dayjs(currentSale.deliveryStart).format('DD/MM/YYYY')} - ${currentSale.deliveryAddressName} a été publiée sur l'espace client`, 'success');
} else {
showSnackbar(`La vente livrée le ${dayjs(currentSale.deliveryStart).format('DD/MM/YYYY')} - ${currentSale.deliveryAddressName} a été retirée de l'espace client`, 'success');
}
} catch {
showSnackbar(`Oops... une erreur s'est produite`, 'error');
}
return <></>
}
}
Loading

0 comments on commit 627ec68

Please sign in to comment.