Added function to manage deliveries
This commit is contained in:
@@ -3,18 +3,55 @@
|
||||
(input)="search.set($any($event.target).value)"/>
|
||||
|
||||
<div class="livraisons-list">
|
||||
@for (deliveryItem of filteredLivraisons(); track deliveryItem.id) {
|
||||
@for (deliveryItem of filteredDeliveries(); track deliveryItem.id) {
|
||||
<div class="livraison-card">
|
||||
<div class="livraison-info">
|
||||
<h3>{{ deliveryItem.client }}</h3>
|
||||
<p class="mr-5">Date d'expédition: {{ deliveryItem.date }}</p>
|
||||
<p>Produits : {{ deliveryItem.produits }}</p>
|
||||
<h3>{{ deliveryItem.delivererTransporter }}</h3>
|
||||
<p class="mr-5">Date d'expédition: {{ deliveryItem.expeditionDate }}</p>
|
||||
<p>Quantité livrée : {{ deliveryItem.products.length }}</p>
|
||||
</div>
|
||||
|
||||
<button nz-button nzType="primary" [nzSize]="size" nzShape="round" (click)="validate(deliveryItem.id)">
|
||||
<nz-icon nzType="check"/>
|
||||
Valider
|
||||
</button>
|
||||
<app-modal-nav #modal name="Valider la livraison" nameIcon="check"
|
||||
(click)="check(deliveryItem.id)"
|
||||
(ok)="validate(deliveryItem.id, selectedWarehouseId!, modal)"
|
||||
(cancel)="reject(modal)">
|
||||
|
||||
<div class="mb-4 flex justify-center">
|
||||
<nz-select
|
||||
[(ngModel)]="selectedWarehouseId"
|
||||
nzPlaceHolder="Sélectionner un entrepôt"
|
||||
required
|
||||
class="w-64">
|
||||
|
||||
@for (wareHouse of wareHouses(); track wareHouse.id) {
|
||||
<nz-option [nzValue]="wareHouse.id" [nzLabel]="wareHouse.name"/>
|
||||
}
|
||||
</nz-select>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="max-height: 400px; overflow-y: auto;">
|
||||
<nz-table [nzData]="filteredDeliveries()"
|
||||
[nzFrontPagination]="false">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th>Réference</th>
|
||||
<th>Nom</th>
|
||||
<th>Quantité</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-center">
|
||||
@for (product of deliveryItem.products; track product.productId) {
|
||||
<tr>
|
||||
<td>{{ product.productReference }}</td>
|
||||
<td>{{ product.productName }}</td>
|
||||
<td>{{ product.quantity }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</nz-table>
|
||||
</div>
|
||||
</app-modal-nav>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,44 +1,120 @@
|
||||
import {Component, computed, signal} from '@angular/core';
|
||||
import {NzButtonComponent, NzButtonSize} from "ng-zorro-antd/button";
|
||||
import {NzIconDirective} from "ng-zorro-antd/icon";
|
||||
import {Component, computed, inject, OnInit, signal} from '@angular/core';
|
||||
import {
|
||||
DeliverynotesService,
|
||||
GetDeliveryNoteDto, GetWareHouseDto,
|
||||
WarehouseproductsService,
|
||||
WarehousesService
|
||||
} from "../../services/api";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
import {NzNotificationService} from "ng-zorro-antd/notification";
|
||||
import {NzTableComponent} from "ng-zorro-antd/table";
|
||||
import {format} from "date-fns";
|
||||
import {ModalNav} from "../modal-nav/modal-nav";
|
||||
import {NzOptionComponent, NzSelectComponent} from "ng-zorro-antd/select";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
|
||||
@Component({
|
||||
selector: 'app-delivery-validator',
|
||||
imports: [
|
||||
NzButtonComponent,
|
||||
NzIconDirective
|
||||
NzTableComponent,
|
||||
ModalNav,
|
||||
NzSelectComponent,
|
||||
NzOptionComponent,
|
||||
FormsModule
|
||||
],
|
||||
templateUrl: './delivery-validator.html',
|
||||
styleUrl: './delivery-validator.css',
|
||||
})
|
||||
export class DeliveryValidator {
|
||||
size: NzButtonSize = 'large';
|
||||
search = signal('');
|
||||
export class DeliveryValidator implements OnInit {
|
||||
private deliveryNotesService = inject(DeliverynotesService);
|
||||
private notificationService = inject(NzNotificationService);
|
||||
private warehousesService = inject(WarehousesService);
|
||||
private warehouseProductsService = inject(WarehouseproductsService);
|
||||
|
||||
livraisons = signal([
|
||||
{id: 1, client: 'Carrefour', date: '2025-02-03', produits: 12},
|
||||
{id: 2, client: 'Intermarché', date: '2025-02-04', produits: 8},
|
||||
{id: 3, client: 'Auchan', date: '2025-02-05', produits: 23},
|
||||
{id: 1, client: 'Carrefour', date: '2025-02-03', produits: 12},
|
||||
{id: 2, client: 'Intermarché', date: '2025-02-04', produits: 8},
|
||||
{id: 3, client: 'Auchan', date: '2025-02-05', produits: 23},
|
||||
{id: 1, client: 'Carrefour', date: '2025-02-03', produits: 12},
|
||||
{id: 2, client: 'Intermarché', date: '2025-02-04', produits: 8},
|
||||
{id: 3, client: 'Auchan', date: '2025-02-05', produits: 23},
|
||||
{id: 1, client: 'Carrefour', date: '2025-02-03', produits: 12},
|
||||
{id: 2, client: 'Intermarché', date: '2025-02-04', produits: 8},
|
||||
{id: 3, client: 'Auchan', date: '2025-02-05', produits: 23}
|
||||
]);
|
||||
search = signal<string>('');
|
||||
deliveryNotes = signal<GetDeliveryNoteDto[]>([]);
|
||||
wareHouses = signal<GetWareHouseDto[]>([]);
|
||||
|
||||
filteredLivraisons = computed(() => {
|
||||
selectedWarehouseId: number | null = null;
|
||||
|
||||
async ngOnInit() {
|
||||
await this.fetchDeliveryNotes();
|
||||
try {
|
||||
const wareHouses = await firstValueFrom(this.warehousesService.getAllWarehouseEndpoint());
|
||||
this.wareHouses.set(wareHouses);
|
||||
} catch {
|
||||
this.notificationService.error(
|
||||
'Erreur',
|
||||
'Erreur de communication avec l\'API'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fetchDeliveryNotes() {
|
||||
try {
|
||||
const deliveries = await firstValueFrom(this.deliveryNotesService.getAllDeliveryNotesNotArrivedEndpoint());
|
||||
this.deliveryNotes.set(deliveries);
|
||||
} catch {
|
||||
this.notificationService.error(
|
||||
'Erreur',
|
||||
'Erreur de communication avec l\'API'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
filteredDeliveries = computed(() => {
|
||||
const query = this.search().toLowerCase();
|
||||
return this.livraisons().filter(l =>
|
||||
l.client.toLowerCase().includes(query) ||
|
||||
l.date.includes(query)
|
||||
return this.deliveryNotes().filter(l =>
|
||||
l.delivererTransporter.toLowerCase().includes(query) ||
|
||||
l.expeditionDate.includes(query)
|
||||
);
|
||||
});
|
||||
|
||||
validate(id: number) {
|
||||
return
|
||||
async check(id: number) {
|
||||
try {
|
||||
const PatchRealDate = {
|
||||
realDeliveryDate: format(new Date(), 'yyyy-MM-dd')
|
||||
};
|
||||
await firstValueFrom(this.deliveryNotesService.patchRealDeliveryDateEndpoint(id, PatchRealDate));
|
||||
} catch (e) {
|
||||
this.notificationService.error(
|
||||
'Erreur',
|
||||
'Erreur de communication avec l\'API',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async validate(id: number, warehouseId: number, modal: ModalNav) {
|
||||
try {
|
||||
const deliveryNote = this.deliveryNotes().find(x => x.id === id);
|
||||
|
||||
for (const product of deliveryNote.products) {
|
||||
await firstValueFrom(this.warehouseProductsService.patchWareHouseProductQuantityEndpoint(
|
||||
product.productId,
|
||||
warehouseId,
|
||||
{
|
||||
quantity: product.quantity
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
this.notificationService.success(
|
||||
'Succès',
|
||||
'Les produits sont bien ajoutés au stock'
|
||||
)
|
||||
|
||||
modal.isVisible = false;
|
||||
await this.fetchDeliveryNotes();
|
||||
} catch {
|
||||
this.notificationService.error(
|
||||
'Erreur',
|
||||
'Vous devez choisir un entrepôt',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async reject(modal: ModalNav) {
|
||||
modal.isVisible = false;
|
||||
await this.fetchDeliveryNotes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {NgStyle} from "@angular/common";
|
||||
})
|
||||
export class InfoCard {
|
||||
icon = input.required<string>()
|
||||
value = input.required<string>()
|
||||
value = input.required<number>()
|
||||
description = input.required<string>()
|
||||
color = input.required<string>()
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
.documents-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start; /* contenu aligné à gauche */
|
||||
gap: 16px; /* espace entre le titre et la liste */
|
||||
margin: 40px 6%;
|
||||
}
|
||||
|
||||
/* Titre */
|
||||
.documents-section h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin: 0; /* on gère l’espace avec le gap */
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: capitalize;
|
||||
border-left: 4px solid #3b82f6;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
/* Liste de documents scrollable */
|
||||
.content {
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
padding: 30px 15px;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.06),
|
||||
0 8px 20px rgba(0, 0, 0, 0.08),
|
||||
0 16px 40px rgba(0, 0, 0, 0.06);
|
||||
max-height: 390px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Chaque carte */
|
||||
.content > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 120px;
|
||||
height: 140px;
|
||||
padding: 12px;
|
||||
background: #ffffff;
|
||||
border-radius: 14px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.2s ease;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content > div:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 10px 22px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.content img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-bottom: 10px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.content p {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
word-break: break-word;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<div class="documents-section">
|
||||
<h1>Documents récents</h1>
|
||||
<div class="content">
|
||||
@for (doc of purchaseOrder(); track doc.id) {
|
||||
<div>
|
||||
<img src="https://cdn-icons-png.flaticon.com/512/337/337946.png" alt="pdf">
|
||||
<p>{{ doc.name }}</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,44 +0,0 @@
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
interface PurchaseOrder {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-info-table',
|
||||
templateUrl: './info-table.html',
|
||||
styleUrls: ['./info-table.css'],
|
||||
})
|
||||
export class InfoTable {
|
||||
docs: PurchaseOrder[] = [
|
||||
{id: 1, name: 'Bon de commande'},
|
||||
{id: 2, name: 'Bon de commande'},
|
||||
{id: 3, name: 'Bon de commande'},
|
||||
{id: 1, name: 'Bon de commande'},
|
||||
{id: 2, name: 'Bon de commande'},
|
||||
{id: 3, name: 'Bon de commande'},
|
||||
{id: 1, name: 'Bon de commande'},
|
||||
{id: 2, name: 'Bon de commande'},
|
||||
{id: 3, name: 'Bon de commande'},
|
||||
{id: 1, name: 'Bon de commande'},
|
||||
{id: 2, name: 'Bon de commande'},
|
||||
{id: 3, name: 'Bon de commande'},
|
||||
{id: 1, name: 'Bon de commande'},
|
||||
{id: 2, name: 'Bon de commande'},
|
||||
{id: 3, name: 'Bon de commande'},
|
||||
{id: 1, name: 'Bon de commande'},
|
||||
{id: 2, name: 'Bon de commande'},
|
||||
{id: 3, name: 'Bon de commande'},
|
||||
{id: 1, name: 'Bon de commande'},
|
||||
{id: 2, name: 'Bon de commande'},
|
||||
{id: 3, name: 'Bon de commande'},
|
||||
{id: 1, name: 'Bon de commande'},
|
||||
{id: 2, name: 'Bon de commande'},
|
||||
{id: 3, name: 'Bon de commande'},
|
||||
];
|
||||
|
||||
purchaseOrder(): PurchaseOrder[] {
|
||||
return this.docs;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user