From 0189fb044062e21e64ee9324148777c10326a2da Mon Sep 17 00:00:00 2001 From: sanchezvem Date: Sat, 29 Nov 2025 23:14:04 +0100 Subject: [PATCH 1/2] connect api to stock page for get, patch and delete --- src/app/components/stock-form/stock-form.html | 6 +- src/app/components/stock-form/stock-form.ts | 25 +-- .../components/stock-table/stock-table.html | 39 ++--- src/app/components/stock-table/stock-table.ts | 143 +++++++++++++----- src/app/pages/stock/stock.html | 12 +- src/app/pages/stock/stock.ts | 51 ++++++- src/app/pages/supplier/supplier.ts | 4 +- src/app/services/api/api/products.service.ts | 53 +++++++ 8 files changed, 255 insertions(+), 78 deletions(-) diff --git a/src/app/components/stock-form/stock-form.html b/src/app/components/stock-form/stock-form.html index d9bcb69..3892c63 100644 --- a/src/app/components/stock-form/stock-form.html +++ b/src/app/components/stock-form/stock-form.html @@ -1,12 +1,12 @@ -
+ Quantité minimale du produit - - + +
\ No newline at end of file diff --git a/src/app/components/stock-form/stock-form.ts b/src/app/components/stock-form/stock-form.ts index c378450..c3934d1 100644 --- a/src/app/components/stock-form/stock-form.ts +++ b/src/app/components/stock-form/stock-form.ts @@ -1,9 +1,10 @@ -import { Component } from '@angular/core'; +import {Component, effect, input} from '@angular/core'; import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms"; import {NzFormControlComponent, NzFormDirective, NzFormItemComponent, NzFormLabelComponent} from "ng-zorro-antd/form"; import {NzInputDirective} from "ng-zorro-antd/input"; import {NzColDirective} from "ng-zorro-antd/grid"; import {NzFlexDirective} from "ng-zorro-antd/flex"; +import {GetProductDto} from "../../services/api"; @Component({ selector: 'app-stock-form', @@ -22,17 +23,19 @@ import {NzFlexDirective} from "ng-zorro-antd/flex"; }) export class StockForm { stockForm = new FormGroup({ - minQuantity: new FormControl(null, [Validators.required]) + id: new FormControl(null), + minimalQuantity: new FormControl(null, [Validators.required]) }) - submitForm() { - // Pour annuler si le formulaire est invalide - if (this.stockForm.invalid) return; - - // Pour obtenir la valeur du formulaire - console.log(this.stockForm.getRawValue()) - - // Pour vider le formulaire - this.stockForm.reset() + product= input(); + constructor() { + effect(() => { + if (this.product()) { + this.stockForm.patchValue({ + id: this.product().id, + minimalQuantity: this.product().minimalQuantity, + }); + } + }); } } \ No newline at end of file diff --git a/src/app/components/stock-table/stock-table.html b/src/app/components/stock-table/stock-table.html index 2ea8bf2..175df95 100644 --- a/src/app/components/stock-table/stock-table.html +++ b/src/app/components/stock-table/stock-table.html @@ -1,6 +1,6 @@ @@ -26,36 +26,39 @@ - @for (data of rowSelectionTable.data; track data.id) { + @for (product of products(); track product.id) { - {{ data.product.name }} - {{ data.product.reference }} - {{ data.product.nec }} - {{ data.product.caliber }} - {{ data.product.weight }} - {{ data.product.duration }} - {{ data.quantity }} - {{ data.product.minimalQuantity }} + {{ product.name }} + {{ product.references }} + {{ product.nec }} + {{ product.caliber }} + {{ product.weight }} + {{ product.duration }} + Quantité totale ??? + {{ product.minimalQuantity }}
- - - + - +
}
+ + \ No newline at end of file diff --git a/src/app/components/stock-table/stock-table.ts b/src/app/components/stock-table/stock-table.ts index cc1ccf5..5550d53 100644 --- a/src/app/components/stock-table/stock-table.ts +++ b/src/app/components/stock-table/stock-table.ts @@ -1,13 +1,14 @@ -import {Component, output} from '@angular/core'; -import {StockInfo} from "../../interfaces/stock.interface"; -import {NzTableComponent} from "ng-zorro-antd/table"; +import {Component, inject, OnInit, output, signal, viewChild} from '@angular/core'; +import {NzTableComponent, NzThMeasureDirective} from "ng-zorro-antd/table"; import {ModalNav} from "../modal-nav/modal-nav"; import {NzIconDirective} from "ng-zorro-antd/icon"; import {StockForm} from "../stock-form/stock-form"; import {NzDividerComponent} from "ng-zorro-antd/divider"; -import {ProductTable} from "../product-table/product-table"; import {FormsModule} from "@angular/forms"; import {NzCheckboxComponent} from "ng-zorro-antd/checkbox"; +import {GetProductDto, ProductsService} from "../../services/api"; +import {NzNotificationService} from "ng-zorro-antd/notification"; +import {firstValueFrom} from "rxjs"; @Component({ selector: 'app-stock-table', @@ -19,38 +20,30 @@ import {NzCheckboxComponent} from "ng-zorro-antd/checkbox"; NzDividerComponent, FormsModule, NzCheckboxComponent, + NzThMeasureDirective, ], templateUrl: './stock-table.html', styleUrl: './stock-table.css', }) -export class StockTable { - listOfData: StockInfo[] = [ - { id: 1, product: ProductTable.listOfProducts[0], quantity: 10 }, - { id: 2, product: ProductTable.listOfProducts[1], quantity: 5 }, - { id: 3, product: ProductTable.listOfProducts[2], quantity: 8 }, - { id: 4, product: ProductTable.listOfProducts[3], quantity: 12 }, - { id: 5, product: ProductTable.listOfProducts[4], quantity: 7 }, - { id: 6, product: ProductTable.listOfProducts[5], quantity: 15 }, - { id: 7, product: ProductTable.listOfProducts[6], quantity: 9 }, - { id: 8, product: ProductTable.listOfProducts[7], quantity: 6 }, - { id: 9, product: ProductTable.listOfProducts[8], quantity: 11 }, - { id: 10, product: ProductTable.listOfProducts[9], quantity: 14 }, - { id: 11, product: ProductTable.listOfProducts[10], quantity: 7 }, - { id: 12, product: ProductTable.listOfProducts[11], quantity: 13 }, - { id: 13, product: ProductTable.listOfProducts[12], quantity: 10 }, - { id: 14, product: ProductTable.listOfProducts[13], quantity: 5 }, - ]; +export class StockTable implements OnInit { + private productsService = inject(ProductsService); + private notificationService = inject(NzNotificationService) + products = signal([]); + productsLoading = signal(false); + updateProduct = viewChild.required('stockForm'); + modal = viewChild.required('modalNav'); checked = false; indeterminate = false; setOfCheckedId = new Set(); + selectionChange = output() + currentPageData: GetProductDto[] = []; get hasSelection(): boolean { return this.setOfCheckedId.size > 0; } - updateCheckedSet(id: number, checked: boolean): void { if (checked) this.setOfCheckedId.add(id); else this.setOfCheckedId.delete(id); @@ -62,31 +55,109 @@ export class StockTable { } onAllChecked(checked: boolean): void { - this.listOfData.forEach(item => this.updateCheckedSet(item.id, checked)); + this.currentPageData.forEach(item => + this.updateCheckedSet(item.id, checked) + ); + this.refreshCheckedStatus(); + } + + onCurrentPageDataChange($event: GetProductDto[]): void { + this.currentPageData = $event; this.refreshCheckedStatus(); } refreshCheckedStatus(): void { - const total = this.listOfData.length; - const checkedCount = this.setOfCheckedId.size; + const total = this.currentPageData.length; + const checkedCount = this.currentPageData.filter(p => this.setOfCheckedId.has(p.id)).length; this.checked = checkedCount === total; this.indeterminate = checkedCount > 0 && checkedCount < total; - // 🔥 Émission asynchrone -> corrige le retard d’affichage - setTimeout(() => { - this.selectionChange.emit(this.hasSelection); - }); + setTimeout(() => this.selectionChange.emit(this.hasSelection)); } - - onCurrentPageDataChange($event: StockInfo[]): void { - this.listOfData = $event; - this.refreshCheckedStatus(); + get selectedIds() { + return Array.from(this.setOfCheckedId); } - delete() { - return; + async ngOnInit() { + await this.fetchProducts(); + } + + async fetchProducts() { + this.productsLoading.set(true) + + try { + const products = await firstValueFrom(this.productsService.getAllProductsEndpoint()) + this.products.set(products); + } catch (e) { + this.notificationService.error( + 'Erreur', + 'Erreur de communication avec l\'API' + ) + } + this.productsLoading.set(false) + } + + async delete(productId:number) { + try { + await firstValueFrom(this.productsService.deleteProductEndpoint(productId)) + this.notificationService.success( + 'Success', + 'Suppression effectuée' + ) + } catch (e) { + this.notificationService.error( + 'Erreur', + 'Impossible de supprimer la ligne' + ) + } + await this.fetchProducts(); + } + + async edit(id: number, updateProductComponent: StockForm) { + if (updateProductComponent.stockForm.invalid) { + this.notificationService.error( + 'Erreur', + 'Erreur d\'écriture dans le formulaire' + ) + return; + } + + try { + + const products = updateProductComponent.stockForm.getRawValue(); + await firstValueFrom(this.productsService.patchProductMinimalStockEndpoint(id, products)) + + this.notificationService.success( + 'Success', + 'Limite de stock modifiée' + ) + } catch (e) { + console.error(e); + this.notificationService.error( + 'Erreur', + 'Erreur lors de la modification' + ) + } + } + + selectedProduct: GetProductDto | null = null; + openEditModal(product: GetProductDto) { + this.selectedProduct = { ...product}; + this.modal().showModal(); + } + + async onModalOk(productId: number, updateProductComponent: StockForm, modal: ModalNav) { + if (!this.selectedProduct) return; + + await this.edit(productId, updateProductComponent); + updateProductComponent.stockForm.reset(); + modal.isVisible = false; + await this.fetchProducts(); + } + + onModalCancel(modal: ModalNav) { + modal.isVisible = false; } - selectionChange = output() } \ No newline at end of file diff --git a/src/app/pages/stock/stock.html b/src/app/pages/stock/stock.html index 97fcb2b..315cffd 100644 --- a/src/app/pages/stock/stock.html +++ b/src/app/pages/stock/stock.html @@ -1,11 +1,11 @@
@if (hasSelection) { - - + + - - + + } @@ -15,7 +15,5 @@
- +
\ No newline at end of file diff --git a/src/app/pages/stock/stock.ts b/src/app/pages/stock/stock.ts index 6d7e544..5fbebf5 100644 --- a/src/app/pages/stock/stock.ts +++ b/src/app/pages/stock/stock.ts @@ -1,9 +1,12 @@ -import { Component } from '@angular/core'; +import {Component, inject, viewChild} from '@angular/core'; import {StockTable} from "../../components/stock-table/stock-table"; import {Search} from "../../components/search/search"; import {ModalButton} from "../../components/modal-button/modal-button"; import {PurchaseOrderForm} from "../../components/purchase-order-form/purchase-order-form"; import {QuotationForm} from "../../components/quotation-form/quotation-form"; +import {ProductsService} from "../../services/api"; +import {NzNotificationService} from "ng-zorro-antd/notification"; +import {firstValueFrom} from "rxjs"; @Component({ selector: 'app-stock', @@ -19,10 +22,56 @@ import {QuotationForm} from "../../components/quotation-form/quotation-form"; }) export class Stock { + modal = viewChild.required('modalButton'); + createQuotation = viewChild.required('quotationForm'); + createPurchaseOrder = viewChild.required('purchaseOrderForm'); + productTable = viewChild.required('stockTable'); + private productsService = inject(ProductsService); + private notificationService = inject(NzNotificationService) + + // async onModalOk() { + // await this.addSupplier() + // this.createSupplier().supplierForm.reset(); + // this.modal().isVisible = false; + // await this.supplierTable().fetchSuppliers() + // } + // + // onModalCancel() { + // this.modal().isVisible = false; + // } + // + // async addSupplier() { + // if (this.createSupplier().supplierForm.invalid) + // { + // this.notificationService.error( + // 'Erreur', + // 'Erreur d\'écriture dans le formulaire' + // ) + // } + // try { + // const suppliers = this.createSupplier().supplierForm.getRawValue(); + // await firstValueFrom(this.usersService.createSupplierEndpoint(suppliers)) + // + // this.notificationService.success( + // 'Success', + // 'Fournisseur enregistré' + // ) + // } catch (e) { + // this.notificationService.error( + // 'Erreur', + // 'Erreur d\'enregistrement' + // ) + // } + // } + hasSelection = false; onSelectionChange(value: boolean) { this.hasSelection = value; } + test(){ + console.log(this.productTable().selectedIds); + } + } diff --git a/src/app/pages/supplier/supplier.ts b/src/app/pages/supplier/supplier.ts index 0a5051f..5cbe79d 100644 --- a/src/app/pages/supplier/supplier.ts +++ b/src/app/pages/supplier/supplier.ts @@ -22,7 +22,7 @@ export class Supplier { modal = viewChild.required('modalButton'); createSupplier = viewChild.required('supplierForm'); supplierTable = viewChild.required('supplierTable'); - private usersService = inject(SuppliersService); + private suppliersService = inject(SuppliersService); private notificationService = inject(NzNotificationService) async onModalOk() { @@ -46,7 +46,7 @@ export class Supplier { } try { const suppliers = this.createSupplier().supplierForm.getRawValue(); - await firstValueFrom(this.usersService.createSupplierEndpoint(suppliers)) + await firstValueFrom(this.suppliersService.createSupplierEndpoint(suppliers)) this.notificationService.success( 'Success', diff --git a/src/app/services/api/api/products.service.ts b/src/app/services/api/api/products.service.ts index c6f3489..65263c5 100644 --- a/src/app/services/api/api/products.service.ts +++ b/src/app/services/api/api/products.service.ts @@ -39,6 +39,59 @@ export class ProductsService extends BaseService { super(basePath, configuration); } + /** + * @endpoint delete /API/products/{productId} + * @param productId + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public deleteProductEndpoint(productId: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined, context?: HttpContext, transferCache?: boolean}): Observable; + public deleteProductEndpoint(productId: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined, context?: HttpContext, transferCache?: boolean}): Observable>; + public deleteProductEndpoint(productId: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined, context?: HttpContext, transferCache?: boolean}): Observable>; + public deleteProductEndpoint(productId: number, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: undefined, context?: HttpContext, transferCache?: boolean}): Observable { + if (productId === null || productId === undefined) { + throw new Error('Required parameter productId was null or undefined when calling deleteProductEndpoint.'); + } + + let localVarHeaders = this.defaultHeaders; + + const localVarHttpHeaderAcceptSelected: string | undefined = options?.httpHeaderAccept ?? this.configuration.selectHeaderAccept([ + ]); + if (localVarHttpHeaderAcceptSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); + } + + const localVarHttpContext: HttpContext = options?.context ?? new HttpContext(); + + const localVarTransferCache: boolean = options?.transferCache ?? true; + + + let responseType_: 'text' | 'json' | 'blob' = 'json'; + if (localVarHttpHeaderAcceptSelected) { + if (localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) { + responseType_ = 'json'; + } else { + responseType_ = 'blob'; + } + } + + let localVarPath = `/API/products/${this.configuration.encodeParam({name: "productId", value: productId, in: "path", style: "simple", explode: false, dataType: "number", dataFormat: "int32"})}`; + const { basePath, withCredentials } = this.configuration; + return this.httpClient.request('delete', `${basePath}${localVarPath}`, + { + context: localVarHttpContext, + responseType: responseType_, + ...(withCredentials ? { withCredentials } : {}), + headers: localVarHeaders, + observe: observe, + ...(localVarTransferCache !== undefined ? { transferCache: localVarTransferCache } : {}), + reportProgress: reportProgress + } + ); + } + /** * @endpoint get /API/products * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. From 5c1403e9345607704c57615118d838301414a52b Mon Sep 17 00:00:00 2001 From: sanchezvem Date: Sun, 30 Nov 2025 11:44:37 +0100 Subject: [PATCH 2/2] fixed errors --- .../components/quotation-form/quotation-form.html | 12 +----------- src/app/components/quotation-form/quotation-form.ts | 11 ----------- src/app/components/stock-table/stock-table.html | 1 + src/app/pages/quotation/quotation.html | 4 ---- src/app/pages/quotation/quotation.ts | 6 ------ 5 files changed, 2 insertions(+), 32 deletions(-) diff --git a/src/app/components/quotation-form/quotation-form.html b/src/app/components/quotation-form/quotation-form.html index 2716fab..0ca8812 100644 --- a/src/app/components/quotation-form/quotation-form.html +++ b/src/app/components/quotation-form/quotation-form.html @@ -1,4 +1,4 @@ -
+ Message du devis @@ -18,15 +18,5 @@ - - - - Fournisseur - - - - - -
diff --git a/src/app/components/quotation-form/quotation-form.ts b/src/app/components/quotation-form/quotation-form.ts index 6db611c..0e7a39c 100644 --- a/src/app/components/quotation-form/quotation-form.ts +++ b/src/app/components/quotation-form/quotation-form.ts @@ -26,15 +26,4 @@ export class QuotationForm { quotationMessage: new FormControl(null), quotationConditionsSale: new FormControl(null), }) - - submitForm() { - // Pour annuler si le formulaire est invalide - if (this.QuotationForm.invalid) return; - - // Pour obtenir la valeur du formulaire - console.log(this.QuotationForm.getRawValue()) - - // Pour vider le formulaire - this.QuotationForm.reset() - } } diff --git a/src/app/components/stock-table/stock-table.html b/src/app/components/stock-table/stock-table.html index 175df95..29daffa 100644 --- a/src/app/components/stock-table/stock-table.html +++ b/src/app/components/stock-table/stock-table.html @@ -1,6 +1,7 @@ diff --git a/src/app/pages/quotation/quotation.html b/src/app/pages/quotation/quotation.html index 2edf3b6..92efc0e 100644 --- a/src/app/pages/quotation/quotation.html +++ b/src/app/pages/quotation/quotation.html @@ -1,8 +1,4 @@
- - - -
diff --git a/src/app/pages/quotation/quotation.ts b/src/app/pages/quotation/quotation.ts index c22b8c2..02508f9 100644 --- a/src/app/pages/quotation/quotation.ts +++ b/src/app/pages/quotation/quotation.ts @@ -1,17 +1,11 @@ import { Component } from '@angular/core'; import {Search} from "../../components/search/search"; -import {DelivereryNoteTable} from "../../components/deliverery-note-table/deliverery-note-table"; -import {ModalButton} from "../../components/modal-button/modal-button"; -import {DelivereryNoteForm} from "../../components/deliverery-note-form/deliverery-note-form"; -import {QuotationForm} from "../../components/quotation-form/quotation-form"; import {QuotationTable} from "../../components/quotation-table/quotation-table"; @Component({ selector: 'app-quotation', imports: [ - ModalButton, Search, - QuotationForm, QuotationTable ], templateUrl: './quotation.html',