restore previous version
This commit is contained in:
@@ -1,78 +0,0 @@
|
|||||||
package fr.gameovergne.api.controller;
|
|
||||||
|
|
||||||
import fr.gameovergne.api.dto.ps.*;
|
|
||||||
import fr.gameovergne.api.model.ps.SimpleResource;
|
|
||||||
import fr.gameovergne.api.service.PrestashopAdminService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/ps-admin")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PrestashopAdminController {
|
|
||||||
|
|
||||||
private final PrestashopAdminService service;
|
|
||||||
|
|
||||||
// --- Simple resources ---
|
|
||||||
|
|
||||||
@GetMapping("/{resource}")
|
|
||||||
public List<PsItemDto> listSimple(@PathVariable SimpleResource resource) {
|
|
||||||
return service.listSimple(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/{resource}")
|
|
||||||
public long createSimple(@PathVariable SimpleResource resource,
|
|
||||||
@RequestParam String name) {
|
|
||||||
return service.createSimple(resource, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{resource}/{id}")
|
|
||||||
public void updateSimple(@PathVariable SimpleResource resource,
|
|
||||||
@PathVariable long id,
|
|
||||||
@RequestParam String name) {
|
|
||||||
service.updateSimple(resource, id, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{resource}/{id}")
|
|
||||||
public void deleteSimple(@PathVariable SimpleResource resource,
|
|
||||||
@PathVariable long id) {
|
|
||||||
service.deleteSimple(resource, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Produits liste + flags + condition values ---
|
|
||||||
|
|
||||||
@GetMapping("/products")
|
|
||||||
public List<ProductListItemDto> listProducts(@RequestParam(required = false) String q) {
|
|
||||||
return service.listProducts(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/products/{id}/flags")
|
|
||||||
public ProductFlagsDto getProductFlags(@PathVariable long id) {
|
|
||||||
return service.getProductFlags(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/meta/condition-values")
|
|
||||||
public List<String> getConditionValues() {
|
|
||||||
return service.getConditionValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Create / update / delete produit ---
|
|
||||||
|
|
||||||
@PostMapping("/products")
|
|
||||||
public long createProduct(@RequestBody PsProductDto dto) {
|
|
||||||
return service.createProduct(dto);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/products/{id}")
|
|
||||||
public void updateProduct(@PathVariable long id,
|
|
||||||
@RequestBody PsProductDto dto) {
|
|
||||||
service.updateProduct(id, dto);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/products/{id}")
|
|
||||||
public void deleteProduct(@PathVariable long id) {
|
|
||||||
service.deleteProduct(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,13 @@ package fr.gameovergne.api.controller;
|
|||||||
|
|
||||||
import fr.gameovergne.api.service.PrestashopClient;
|
import fr.gameovergne.api.service.PrestashopClient;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/ps")
|
@RequestMapping("/api/ps")
|
||||||
@@ -15,13 +20,24 @@ public class PrestashopProxyController {
|
|||||||
this.prestashopClient = prestashopClient;
|
this.prestashopClient = prestashopClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{resource}")
|
@GetMapping("/**")
|
||||||
public ResponseEntity<String> proxyGet(
|
public ResponseEntity<String> proxyGet(HttpServletRequest request) {
|
||||||
@PathVariable String resource,
|
String fullPath = (String) request.getAttribute(
|
||||||
HttpServletRequest request
|
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
|
||||||
) {
|
String bestMatchPattern = (String) request.getAttribute(
|
||||||
String rawQuery = request.getQueryString(); // ex: "display=%5Bid,name,active%5D&output_format=JSON"
|
HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
||||||
String body = prestashopClient.getWithRawQuery(resource, rawQuery);
|
|
||||||
return ResponseEntity.ok(body);
|
String relativePath = new AntPathMatcher()
|
||||||
|
.extractPathWithinPattern(bestMatchPattern, fullPath);
|
||||||
|
|
||||||
|
String rawQuery = request.getQueryString();
|
||||||
|
|
||||||
|
ResponseEntity<String> prestaResponse =
|
||||||
|
prestashopClient.getWithRawQuery("/" + relativePath, rawQuery);
|
||||||
|
|
||||||
|
return ResponseEntity
|
||||||
|
.status(prestaResponse.getStatusCode())
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body(prestaResponse.getBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package fr.gameovergne.api.dto.ps;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
@Value
|
|
||||||
@Builder
|
|
||||||
public class ProductFlagsDto {
|
|
||||||
boolean complete;
|
|
||||||
boolean hasManual;
|
|
||||||
String conditionLabel;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package fr.gameovergne.api.dto.ps;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
@Value
|
|
||||||
@Builder
|
|
||||||
public class ProductListItemDto {
|
|
||||||
Long id;
|
|
||||||
String name;
|
|
||||||
Long manufacturerId;
|
|
||||||
Long supplierId;
|
|
||||||
Long categoryId;
|
|
||||||
Double priceHt;
|
|
||||||
Integer quantity;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package fr.gameovergne.api.dto.ps;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
@Value
|
|
||||||
@Builder
|
|
||||||
public class PsItemDto {
|
|
||||||
Long id;
|
|
||||||
String name;
|
|
||||||
Boolean active;
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package fr.gameovergne.api.dto.ps;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
@Value
|
|
||||||
@Builder
|
|
||||||
public class PsProductDto {
|
|
||||||
Long id; // optionnel pour update
|
|
||||||
String name;
|
|
||||||
|
|
||||||
Long manufacturerId;
|
|
||||||
Long supplierId;
|
|
||||||
Long categoryId;
|
|
||||||
|
|
||||||
Double priceTtc;
|
|
||||||
Double vatRate;
|
|
||||||
|
|
||||||
Integer quantity;
|
|
||||||
|
|
||||||
Boolean complete; // Complet: Oui/Non
|
|
||||||
Boolean hasManual; // Notice: Avec/Sans
|
|
||||||
String conditionLabel; // État: libellé
|
|
||||||
|
|
||||||
String description; // description libre
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package fr.gameovergne.api.model.ps;
|
|
||||||
|
|
||||||
public enum SimpleResource {
|
|
||||||
categories("categories", "category", true, true),
|
|
||||||
manufacturers("manufacturers", "manufacturer", false, false),
|
|
||||||
suppliers("suppliers", "supplier", false, false);
|
|
||||||
|
|
||||||
public final String path;
|
|
||||||
public final String root;
|
|
||||||
public final boolean needsDefaultLang;
|
|
||||||
public final boolean nameIsMultilang;
|
|
||||||
|
|
||||||
SimpleResource(String path, String root, boolean needsDefaultLang, boolean nameIsMultilang) {
|
|
||||||
this.path = path;
|
|
||||||
this.root = root;
|
|
||||||
this.needsDefaultLang = needsDefaultLang;
|
|
||||||
this.nameIsMultilang = nameIsMultilang;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,17 @@
|
|||||||
// package à adapter si besoin
|
|
||||||
package fr.gameovergne.api.service;
|
package fr.gameovergne.api.service;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.client.RestClient;
|
import org.springframework.web.client.RestClient;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.Base64;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -21,176 +19,104 @@ public class PrestashopClient {
|
|||||||
|
|
||||||
private final RestClient client;
|
private final RestClient client;
|
||||||
private final String baseUrl;
|
private final String baseUrl;
|
||||||
private final String apiKey;
|
|
||||||
|
|
||||||
public PrestashopClient(
|
public PrestashopClient(
|
||||||
@Value("${prestashop.api.base-url}") String baseUrl,
|
@Value("${prestashop.base-url}") String baseUrl,
|
||||||
@Value("${prestashop.api.key}") String apiKey
|
@Value("${prestashop.api-key}") String apiKey
|
||||||
) {
|
) {
|
||||||
this.baseUrl = baseUrl; // ex: https://shop.gameovergne.fr/api
|
this.baseUrl = baseUrl;
|
||||||
this.apiKey = apiKey;
|
|
||||||
|
String basicAuth = Base64.getEncoder()
|
||||||
|
.encodeToString((apiKey + ":").getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
this.client = RestClient.builder()
|
||||||
|
.defaultHeader(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth)
|
||||||
|
.build();
|
||||||
|
|
||||||
log.info("[PrestaShop] Base URL = {}", baseUrl);
|
log.info("[PrestaShop] Base URL = {}", baseUrl);
|
||||||
log.info("[PrestaShop] API key length = {}", apiKey.length());
|
log.info("[PrestaShop] API key length = {}", apiKey.length());
|
||||||
|
|
||||||
this.client = RestClient.builder()
|
|
||||||
.defaultHeaders(headers -> {
|
|
||||||
headers.set(HttpHeaders.USER_AGENT, "curl/8.10.1");
|
|
||||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.ALL));
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
private String buildUri(String path, MultiValueMap<String, String> params) {
|
||||||
// Outil interne : construit l’URL complète baseUrl + path + ?ws_key=...¶ms...
|
UriComponentsBuilder builder = UriComponentsBuilder
|
||||||
// ------------------------------------------------------------------------
|
.fromHttpUrl(baseUrl + path);
|
||||||
private String buildUrl(String path, MultiValueMap<String, String> params) {
|
|
||||||
StringBuilder full = new StringBuilder();
|
|
||||||
|
|
||||||
// baseUrl
|
|
||||||
full.append(baseUrl);
|
|
||||||
|
|
||||||
// path
|
|
||||||
if (path != null && !path.isBlank()) {
|
|
||||||
boolean baseEndsWithSlash = baseUrl.endsWith("/");
|
|
||||||
boolean pathStartsWithSlash = path.startsWith("/");
|
|
||||||
|
|
||||||
if (baseEndsWithSlash && pathStartsWithSlash) {
|
|
||||||
full.append(path.substring(1));
|
|
||||||
} else if (!baseEndsWithSlash && !pathStartsWithSlash) {
|
|
||||||
full.append("/").append(path);
|
|
||||||
} else {
|
|
||||||
full.append(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ws_key en premier param
|
|
||||||
full.append("?ws_key=").append(URLEncoder.encode(apiKey, StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
if (params != null && !params.isEmpty()) {
|
if (params != null && !params.isEmpty()) {
|
||||||
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
|
builder.queryParams(params);
|
||||||
String key = entry.getKey();
|
|
||||||
for (String value : entry.getValue()) {
|
|
||||||
full.append("&")
|
|
||||||
.append(URLEncoder.encode(key, StandardCharsets.UTF_8))
|
|
||||||
.append("=")
|
|
||||||
.append(URLEncoder.encode(value, StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return builder.build(true).toUriString();
|
||||||
}
|
}
|
||||||
|
|
||||||
String url = full.toString();
|
// -------- Méthodes "typed" JSON / XML utilisées par ps-admin --------
|
||||||
log.debug("[PrestaShop] Built URL = {}", url);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// GET JSON (utilisé partout dans PrestashopAdminService)
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
public String getJson(String path, MultiValueMap<String, String> params) {
|
public String getJson(String path, MultiValueMap<String, String> params) {
|
||||||
String url = buildUrl(path, params);
|
String uri = buildUri(path, params);
|
||||||
log.info("[PrestaShop] GET JSON {}", url);
|
log.info("[PrestaShop] GET JSON {}", uri);
|
||||||
|
|
||||||
return client.get()
|
return client.get()
|
||||||
.uri(URI.create(url))
|
.uri(uri)
|
||||||
.accept(MediaType.APPLICATION_JSON)
|
.accept(MediaType.APPLICATION_JSON)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.body(String.class);
|
.body(String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// GET XML (utilisé pour certains appels de stock, produit, etc.)
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
public String getXml(String path, MultiValueMap<String, String> params) {
|
public String getXml(String path, MultiValueMap<String, String> params) {
|
||||||
String url = buildUrl(path, params);
|
String uri = buildUri(path, params);
|
||||||
log.info("[PrestaShop] GET XML {}", url);
|
log.info("[PrestaShop] GET XML {}", uri);
|
||||||
|
|
||||||
return client.get()
|
return client.get()
|
||||||
.uri(URI.create(url))
|
.uri(uri)
|
||||||
.accept(MediaType.APPLICATION_XML)
|
.accept(MediaType.APPLICATION_XML)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.body(String.class);
|
.body(String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// POST XML (création catégorie/produit/etc.)
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
public String postXml(String path, MultiValueMap<String, String> params, String xmlBody) {
|
public String postXml(String path, MultiValueMap<String, String> params, String xmlBody) {
|
||||||
String url = buildUrl(path, params);
|
String uri = buildUri(path, params);
|
||||||
log.info("[PrestaShop] POST XML {} (body length={})", url, xmlBody != null ? xmlBody.length() : 0);
|
log.info("[PrestaShop] POST XML {}", uri);
|
||||||
|
|
||||||
return client.post()
|
return client.post()
|
||||||
.uri(URI.create(url))
|
.uri(uri)
|
||||||
.contentType(MediaType.APPLICATION_XML)
|
.contentType(MediaType.APPLICATION_XML)
|
||||||
.accept(MediaType.APPLICATION_XML)
|
.body(xmlBody)
|
||||||
.body(xmlBody != null ? xmlBody : "")
|
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.body(String.class);
|
.body(String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// PUT XML (update catégorie/produit/stock/etc.)
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
public String putXml(String path, MultiValueMap<String, String> params, String xmlBody) {
|
public String putXml(String path, MultiValueMap<String, String> params, String xmlBody) {
|
||||||
String url = buildUrl(path, params);
|
String uri = buildUri(path, params);
|
||||||
log.info("[PrestaShop] PUT XML {} (body length={})", url, xmlBody != null ? xmlBody.length() : 0);
|
log.info("[PrestaShop] PUT XML {}", uri);
|
||||||
|
|
||||||
return client.put()
|
return client.put()
|
||||||
.uri(URI.create(url))
|
.uri(uri)
|
||||||
.contentType(MediaType.APPLICATION_XML)
|
.contentType(MediaType.APPLICATION_XML)
|
||||||
.accept(MediaType.APPLICATION_XML)
|
.body(xmlBody)
|
||||||
.body(xmlBody != null ? xmlBody : "")
|
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.body(String.class);
|
.body(String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// DELETE (suppression ressource)
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
public void delete(String path, MultiValueMap<String, String> params) {
|
public void delete(String path, MultiValueMap<String, String> params) {
|
||||||
String url = buildUrl(path, params);
|
String uri = buildUri(path, params);
|
||||||
log.info("[PrestaShop] DELETE {}", url);
|
log.info("[PrestaShop] DELETE {}", uri);
|
||||||
|
|
||||||
client.delete()
|
client.delete()
|
||||||
.uri(URI.create(url))
|
.uri(uri)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.toBodilessEntity();
|
.toBodilessEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// -------- Méthode générique utilisée par le proxy /api/ps/** --------
|
||||||
// Spécial proxy GET brut : on garde la query telle quelle (déjà encodée)
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
public String getWithRawQuery(String resource, String rawQuery) {
|
|
||||||
try {
|
|
||||||
StringBuilder fullUrl = new StringBuilder();
|
|
||||||
fullUrl.append(baseUrl);
|
|
||||||
// baseUrl : https://shop.gameovergne.fr/api
|
|
||||||
if (!baseUrl.endsWith("/")) {
|
|
||||||
fullUrl.append("/");
|
|
||||||
}
|
|
||||||
// resource : "categories", "products", ...
|
|
||||||
fullUrl.append(resource);
|
|
||||||
|
|
||||||
// ws_key
|
/**
|
||||||
String encodedKey = URLEncoder.encode(apiKey, StandardCharsets.UTF_8);
|
* Proxy brut : on lui donne le path Presta (ex: "/categories") et la query string déjà encodée.
|
||||||
fullUrl.append("?ws_key=").append(encodedKey);
|
* On récupère un ResponseEntity<String> pour pouvoir propager le status code.
|
||||||
|
*/
|
||||||
// rawQuery = "display=%5Bid,name,active%5D&output_format=JSON"
|
public ResponseEntity<String> getWithRawQuery(String path, String rawQuery) {
|
||||||
|
String uri = baseUrl + path;
|
||||||
if (rawQuery != null && !rawQuery.isBlank()) {
|
if (rawQuery != null && !rawQuery.isBlank()) {
|
||||||
fullUrl.append("&").append(rawQuery); // surtout ne pas réencoder
|
uri = uri + "?" + rawQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
String urlString = fullUrl.toString();
|
log.info("[PrestaShop] GET (proxy) {}", uri);
|
||||||
log.info("[PrestaShop] RAW GET via ws_key = {}", urlString);
|
|
||||||
|
|
||||||
return client.get()
|
return client.get()
|
||||||
.uri(URI.create(urlString))
|
.uri(uri)
|
||||||
|
.accept(MediaType.APPLICATION_JSON)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.body(String.class);
|
.toEntity(String.class);
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("[PrestaShop] getWithRawQuery error for resource={} rawQuery={}", resource, rawQuery, e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// File: src/app/components/ps-product-dialog/ps-product-dialog.component.ts
|
|
||||||
import {Component, Inject, OnInit, inject, OnDestroy} from '@angular/core';
|
import {Component, Inject, OnInit, inject, OnDestroy} from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
@@ -21,7 +20,6 @@ import { catchError, forkJoin, of, Observable } from 'rxjs';
|
|||||||
import { PsItem } from '../../interfaces/ps-item';
|
import { PsItem } from '../../interfaces/ps-item';
|
||||||
import { ProductListItem } from '../../interfaces/product-list-item';
|
import { ProductListItem } from '../../interfaces/product-list-item';
|
||||||
import { PrestashopService } from '../../services/prestashop.serivce';
|
import { PrestashopService } from '../../services/prestashop.serivce';
|
||||||
import { PsProduct } from '../../interfaces/ps-product'; // si tu as une interface dédiée
|
|
||||||
|
|
||||||
export type ProductDialogData = {
|
export type ProductDialogData = {
|
||||||
mode: 'create' | 'edit';
|
mode: 'create' | 'edit';
|
||||||
@@ -89,7 +87,6 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// ---------- Helpers locaux ----------
|
// ---------- Helpers locaux ----------
|
||||||
|
|
||||||
// utilisé seulement pour pré-afficher un TTC approximatif à partir du HT de la liste
|
|
||||||
private toTtc(ht: number) {
|
private toTtc(ht: number) {
|
||||||
return Math.round(((ht * 1.2) + Number.EPSILON) * 100) / 100;
|
return Math.round(((ht * 1.2) + Number.EPSILON) * 100) / 100;
|
||||||
}
|
}
|
||||||
@@ -151,7 +148,6 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
|
|||||||
if (this.mode === 'edit' && this.productRow) {
|
if (this.mode === 'edit' && this.productRow) {
|
||||||
const r = this.productRow;
|
const r = this.productRow;
|
||||||
|
|
||||||
// pré-remplissage rapide avec la ligne de liste (HT -> TTC approximatif)
|
|
||||||
const immediateTtc = r.priceHt == null ? 0 : this.toTtc(r.priceHt);
|
const immediateTtc = r.priceHt == null ? 0 : this.toTtc(r.priceHt);
|
||||||
this.form.patchValue({
|
this.form.patchValue({
|
||||||
name: r.name,
|
name: r.name,
|
||||||
@@ -162,7 +158,11 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const details$ = this.ps.getProductDetails(r.id).pipe(
|
const details$ = this.ps.getProductDetails(r.id).pipe(
|
||||||
catchError(() => of<PsProduct | null>(null))
|
catchError(() => of({
|
||||||
|
id: r.id, name: r.name, description: '',
|
||||||
|
id_manufacturer: r.id_manufacturer, id_supplier: r.id_supplier,
|
||||||
|
id_category_default: r.id_category_default, priceHt: r.priceHt ?? 0
|
||||||
|
}))
|
||||||
);
|
);
|
||||||
const qty$ = this.ps.getProductQuantity(r.id).pipe(catchError(() => of(0)));
|
const qty$ = this.ps.getProductQuantity(r.id).pipe(catchError(() => of(0)));
|
||||||
const imgs$ = this.ps.getProductImageUrls(r.id).pipe(catchError(() => of<string[]>([])));
|
const imgs$ = this.ps.getProductImageUrls(r.id).pipe(catchError(() => of<string[]>([])));
|
||||||
@@ -172,23 +172,20 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
forkJoin({ details: details$, qty: qty$, imgs: imgs$, flags: flags$ })
|
forkJoin({ details: details$, qty: qty$, imgs: imgs$, flags: flags$ })
|
||||||
.subscribe(({ details, qty, imgs, flags }) => {
|
.subscribe(({ details, qty, imgs, flags }) => {
|
||||||
const baseDesc = this.cleanForTextarea(details?.description ?? '');
|
const ttc = this.toTtc(details.priceHt ?? 0);
|
||||||
|
const baseDesc = this.cleanForTextarea(details.description ?? '');
|
||||||
this.lastLoadedDescription = baseDesc;
|
this.lastLoadedDescription = baseDesc;
|
||||||
|
|
||||||
this.form.patchValue({
|
this.form.patchValue({
|
||||||
// description depuis le backend (déjà propre / nettoyée normalement)
|
|
||||||
description: baseDesc,
|
description: baseDesc,
|
||||||
// flags
|
|
||||||
complete: flags.complete,
|
complete: flags.complete,
|
||||||
hasManual: flags.hasManual,
|
hasManual: flags.hasManual,
|
||||||
conditionLabel: flags.conditionLabel || '',
|
conditionLabel: flags.conditionLabel || '',
|
||||||
// TTC "réel" calculé par le backend (si dispo) sinon on garde la valeur actuelle
|
priceTtc: (ttc || this.form.value.priceTtc || 0),
|
||||||
priceTtc: (details?.priceTtc ?? this.form.value.priceTtc ?? 0),
|
|
||||||
quantity: qty,
|
quantity: qty,
|
||||||
// ids de ref issus du DTO backend
|
categoryId: (details.id_category_default ?? this.form.value.categoryId) ?? null,
|
||||||
categoryId: (details?.categoryId ?? this.form.value.categoryId) ?? null,
|
manufacturerId: (details.id_manufacturer ?? this.form.value.manufacturerId) ?? null,
|
||||||
manufacturerId: (details?.manufacturerId ?? this.form.value.manufacturerId) ?? null,
|
supplierId: (details.id_supplier ?? this.form.value.supplierId) ?? null
|
||||||
supplierId: (details?.supplierId ?? this.form.value.supplierId) ?? null
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.existingImageUrls = imgs;
|
this.existingImageUrls = imgs;
|
||||||
@@ -264,7 +261,7 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------- Save / close --------
|
// -------- Save / close inchangés (à part dto.images) --------
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
if (this.form.invalid) return;
|
if (this.form.invalid) return;
|
||||||
@@ -272,7 +269,7 @@ export class PsProductDialogComponent implements OnInit, OnDestroy {
|
|||||||
const v = this.form.getRawValue();
|
const v = this.form.getRawValue();
|
||||||
const effectiveDescription = (v.description ?? '').trim() || this.lastLoadedDescription;
|
const effectiveDescription = (v.description ?? '').trim() || this.lastLoadedDescription;
|
||||||
|
|
||||||
const dto: PsProduct = {
|
const dto = {
|
||||||
name: v.name!,
|
name: v.name!,
|
||||||
description: effectiveDescription,
|
description: effectiveDescription,
|
||||||
categoryId: +v.categoryId!,
|
categoryId: +v.categoryId!,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user