Feat: front-end service et store pour les sous traitant
This commit is contained in:
parent
7506bdcf8b
commit
8c6787d03e
@ -1,3 +1,4 @@
|
|||||||
export * from "./http";
|
export * from "./http";
|
||||||
export { default as AuthService } from "./auth";
|
export { default as AuthService } from "./auth";
|
||||||
export { default as WebmailService } from "./webmail";
|
export { default as WebmailService } from "./webmail";
|
||||||
|
export { default as SousTraitantService } from "./sousTraitant";
|
||||||
|
|||||||
189
thanasoft-front/src/services/sousTraitant.ts
Normal file
189
thanasoft-front/src/services/sousTraitant.ts
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import { request } from "./http";
|
||||||
|
|
||||||
|
export type SousTraitantStatut = "actif" | "inactif" | "en_evaluation";
|
||||||
|
|
||||||
|
export interface SousTraitant {
|
||||||
|
id: number;
|
||||||
|
nom_entreprise: string;
|
||||||
|
siret: string | null;
|
||||||
|
forme_juridique: string | null;
|
||||||
|
code_ape: string | null;
|
||||||
|
adresse: string | null;
|
||||||
|
contact_principal: string;
|
||||||
|
telephone: string | null;
|
||||||
|
email: string | null;
|
||||||
|
site_web: string | null;
|
||||||
|
numero_contrat: string | null;
|
||||||
|
montant_contrat: string | number | null;
|
||||||
|
date_debut_contrat: string | null;
|
||||||
|
date_fin_contrat: string | null;
|
||||||
|
type_prestation: string | null;
|
||||||
|
conditions_paiement: string | null;
|
||||||
|
statut: SousTraitantStatut;
|
||||||
|
note_qualite: string | number | null;
|
||||||
|
certifications_labels: string[];
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SousTraitantListResponse {
|
||||||
|
data: SousTraitant[];
|
||||||
|
meta?: {
|
||||||
|
current_page: number;
|
||||||
|
last_page: number;
|
||||||
|
per_page: number;
|
||||||
|
total: number;
|
||||||
|
from?: number;
|
||||||
|
to?: number;
|
||||||
|
stats?: {
|
||||||
|
actif: number;
|
||||||
|
inactif: number;
|
||||||
|
en_evaluation: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SousTraitantResponse {
|
||||||
|
data: SousTraitant;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateSousTraitantPayload {
|
||||||
|
nom_entreprise: string;
|
||||||
|
siret?: string | null;
|
||||||
|
forme_juridique?: string | null;
|
||||||
|
code_ape?: string | null;
|
||||||
|
adresse?: string | null;
|
||||||
|
contact_principal: string;
|
||||||
|
telephone?: string | null;
|
||||||
|
email?: string | null;
|
||||||
|
site_web?: string | null;
|
||||||
|
numero_contrat?: string | null;
|
||||||
|
montant_contrat?: number | string | null;
|
||||||
|
date_debut_contrat?: string | null;
|
||||||
|
date_fin_contrat?: string | null;
|
||||||
|
type_prestation?: string | null;
|
||||||
|
conditions_paiement?: string | null;
|
||||||
|
statut?: SousTraitantStatut;
|
||||||
|
note_qualite?: number | string | null;
|
||||||
|
certifications_labels?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateSousTraitantPayload
|
||||||
|
extends Partial<CreateSousTraitantPayload> {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SousTraitantService = {
|
||||||
|
async getAllSousTraitants(params?: {
|
||||||
|
page?: number;
|
||||||
|
per_page?: number;
|
||||||
|
search?: string;
|
||||||
|
statut?: SousTraitantStatut;
|
||||||
|
sort_by?: string;
|
||||||
|
sort_direction?: "asc" | "desc";
|
||||||
|
}): Promise<SousTraitantListResponse> {
|
||||||
|
const response = await request<SousTraitantListResponse>({
|
||||||
|
url: "/api/sous-traitants",
|
||||||
|
method: "get",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
|
||||||
|
async getSousTraitant(id: number): Promise<SousTraitantResponse> {
|
||||||
|
const response = await request<SousTraitantResponse>({
|
||||||
|
url: `/api/sous-traitants/${id}`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
|
||||||
|
async createSousTraitant(
|
||||||
|
payload: CreateSousTraitantPayload
|
||||||
|
): Promise<SousTraitantResponse> {
|
||||||
|
const formattedPayload = this.transformSousTraitantPayload(payload);
|
||||||
|
|
||||||
|
const response = await request<SousTraitantResponse>({
|
||||||
|
url: "/api/sous-traitants",
|
||||||
|
method: "post",
|
||||||
|
data: formattedPayload,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
|
||||||
|
async updateSousTraitant(
|
||||||
|
payload: UpdateSousTraitantPayload
|
||||||
|
): Promise<SousTraitantResponse> {
|
||||||
|
const { id, ...updateData } = payload;
|
||||||
|
const formattedPayload = this.transformSousTraitantPayload(updateData);
|
||||||
|
|
||||||
|
const response = await request<SousTraitantResponse>({
|
||||||
|
url: `/api/sous-traitants/${id}`,
|
||||||
|
method: "put",
|
||||||
|
data: formattedPayload,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteSousTraitant(
|
||||||
|
id: number
|
||||||
|
): Promise<{ success?: boolean; message: string }> {
|
||||||
|
const response = await request<{ success?: boolean; message: string }>({
|
||||||
|
url: `/api/sous-traitants/${id}`,
|
||||||
|
method: "delete",
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
|
||||||
|
transformSousTraitantPayload(
|
||||||
|
payload: Partial<CreateSousTraitantPayload>
|
||||||
|
): Record<string, unknown> {
|
||||||
|
const transformed: Record<string, unknown> = { ...payload };
|
||||||
|
|
||||||
|
if (
|
||||||
|
Array.isArray(transformed.certifications_labels) &&
|
||||||
|
transformed.certifications_labels.length > 0
|
||||||
|
) {
|
||||||
|
transformed.certifications_labels = transformed.certifications_labels
|
||||||
|
.map((item) => (typeof item === "string" ? item.trim() : item))
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(transformed).forEach((key) => {
|
||||||
|
if (transformed[key] === undefined) {
|
||||||
|
delete transformed[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return transformed;
|
||||||
|
},
|
||||||
|
|
||||||
|
async searchSousTraitants(
|
||||||
|
query: string,
|
||||||
|
params?: {
|
||||||
|
exact_match?: boolean;
|
||||||
|
}
|
||||||
|
): Promise<SousTraitant[]> {
|
||||||
|
const response = await request<{
|
||||||
|
data: SousTraitant[];
|
||||||
|
count: number;
|
||||||
|
message: string;
|
||||||
|
}>({
|
||||||
|
url: "/api/sous-traitants/searchBy",
|
||||||
|
method: "get",
|
||||||
|
params: {
|
||||||
|
name: query,
|
||||||
|
exact_match: params?.exact_match || false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SousTraitantService;
|
||||||
345
thanasoft-front/src/stores/sousTraitantStore.ts
Normal file
345
thanasoft-front/src/stores/sousTraitantStore.ts
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
import SousTraitantService from "@/services/sousTraitant";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
CreateSousTraitantPayload,
|
||||||
|
SousTraitant,
|
||||||
|
SousTraitantStatut,
|
||||||
|
UpdateSousTraitantPayload,
|
||||||
|
} from "@/services/sousTraitant";
|
||||||
|
|
||||||
|
export const useSousTraitantStore = defineStore("sousTraitant", () => {
|
||||||
|
const sousTraitants = ref<SousTraitant[]>([]);
|
||||||
|
const currentSousTraitant = ref<SousTraitant | null>(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
const searchResults = ref<SousTraitant[]>([]);
|
||||||
|
const filters = ref<{
|
||||||
|
page: number;
|
||||||
|
per_page: number;
|
||||||
|
search?: string;
|
||||||
|
statut?: SousTraitantStatut;
|
||||||
|
sort_by?: string;
|
||||||
|
sort_direction?: "asc" | "desc";
|
||||||
|
}>({
|
||||||
|
page: 1,
|
||||||
|
per_page: 10,
|
||||||
|
sort_by: "created_at",
|
||||||
|
sort_direction: "desc",
|
||||||
|
});
|
||||||
|
|
||||||
|
const pagination = ref({
|
||||||
|
current_page: 1,
|
||||||
|
last_page: 1,
|
||||||
|
per_page: 10,
|
||||||
|
total: 0,
|
||||||
|
from: 0,
|
||||||
|
to: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const allSousTraitants = computed(() => sousTraitants.value);
|
||||||
|
const activeSousTraitants = computed(() =>
|
||||||
|
sousTraitants.value.filter((item) => item.statut === "actif")
|
||||||
|
);
|
||||||
|
const inactiveSousTraitants = computed(() =>
|
||||||
|
sousTraitants.value.filter((item) => item.statut === "inactif")
|
||||||
|
);
|
||||||
|
const evaluatingSousTraitants = computed(() =>
|
||||||
|
sousTraitants.value.filter((item) => item.statut === "en_evaluation")
|
||||||
|
);
|
||||||
|
const isLoading = computed(() => loading.value);
|
||||||
|
const hasError = computed(() => error.value !== null);
|
||||||
|
const getError = computed(() => error.value);
|
||||||
|
const getPagination = computed(() => pagination.value);
|
||||||
|
const getSousTraitantById = computed(() => (id: number) =>
|
||||||
|
sousTraitants.value.find((item) => item.id === id)
|
||||||
|
);
|
||||||
|
|
||||||
|
const setLoading = (isLoading: boolean) => {
|
||||||
|
loading.value = isLoading;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setError = (err: string | null) => {
|
||||||
|
error.value = err;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearError = () => {
|
||||||
|
error.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSousTraitants = (items: SousTraitant[]) => {
|
||||||
|
sousTraitants.value = items;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCurrentSousTraitant = (item: SousTraitant | null) => {
|
||||||
|
currentSousTraitant.value = item;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSearchResults = (items: SousTraitant[]) => {
|
||||||
|
searchResults.value = items;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setPagination = (meta: any) => {
|
||||||
|
if (meta) {
|
||||||
|
const getValue = (val: any) => (Array.isArray(val) ? val[0] : val);
|
||||||
|
pagination.value = {
|
||||||
|
current_page: Number(getValue(meta.current_page)) || 1,
|
||||||
|
last_page: Number(getValue(meta.last_page)) || 1,
|
||||||
|
per_page: Number(getValue(meta.per_page)) || 10,
|
||||||
|
total: Number(getValue(meta.total)) || 0,
|
||||||
|
from: Number(getValue(meta.from)) || 0,
|
||||||
|
to: Number(getValue(meta.to)) || 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
filters.value = {
|
||||||
|
...filters.value,
|
||||||
|
page: pagination.value.current_page,
|
||||||
|
per_page: pagination.value.per_page,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setFilters = (params?: {
|
||||||
|
page?: number;
|
||||||
|
per_page?: number;
|
||||||
|
search?: string;
|
||||||
|
statut?: SousTraitantStatut;
|
||||||
|
sort_by?: string;
|
||||||
|
sort_direction?: "asc" | "desc";
|
||||||
|
}) => {
|
||||||
|
filters.value = {
|
||||||
|
...filters.value,
|
||||||
|
...params,
|
||||||
|
page: params?.page ?? filters.value.page ?? 1,
|
||||||
|
per_page: params?.per_page ?? filters.value.per_page ?? 10,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchSousTraitants = async (params?: {
|
||||||
|
page?: number;
|
||||||
|
per_page?: number;
|
||||||
|
search?: string;
|
||||||
|
statut?: SousTraitantStatut;
|
||||||
|
sort_by?: string;
|
||||||
|
sort_direction?: "asc" | "desc";
|
||||||
|
}) => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
setFilters(params);
|
||||||
|
|
||||||
|
const requestParams = Object.fromEntries(
|
||||||
|
Object.entries(filters.value).filter(
|
||||||
|
([, value]) => value !== undefined && value !== null && value !== ""
|
||||||
|
)
|
||||||
|
) as {
|
||||||
|
page?: number;
|
||||||
|
per_page?: number;
|
||||||
|
search?: string;
|
||||||
|
statut?: SousTraitantStatut;
|
||||||
|
sort_by?: string;
|
||||||
|
sort_direction?: "asc" | "desc";
|
||||||
|
};
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await SousTraitantService.getAllSousTraitants(requestParams);
|
||||||
|
setSousTraitants(response.data);
|
||||||
|
if (response.meta) {
|
||||||
|
setPagination(response.meta);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
} catch (err: any) {
|
||||||
|
const errorMessage =
|
||||||
|
err.response?.data?.message ||
|
||||||
|
err.message ||
|
||||||
|
"Failed to fetch sous-traitants";
|
||||||
|
setError(errorMessage);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchSousTraitant = async (id: number) => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await SousTraitantService.getSousTraitant(id);
|
||||||
|
setCurrentSousTraitant(response.data);
|
||||||
|
return response.data;
|
||||||
|
} catch (err: any) {
|
||||||
|
const errorMessage =
|
||||||
|
err.response?.data?.message ||
|
||||||
|
err.message ||
|
||||||
|
"Failed to fetch sous-traitant";
|
||||||
|
setError(errorMessage);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const createSousTraitant = async (payload: CreateSousTraitantPayload) => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await SousTraitantService.createSousTraitant(payload);
|
||||||
|
sousTraitants.value.push(response.data);
|
||||||
|
setCurrentSousTraitant(response.data);
|
||||||
|
return response.data;
|
||||||
|
} catch (err: any) {
|
||||||
|
const errorMessage =
|
||||||
|
err.response?.data?.message ||
|
||||||
|
err.message ||
|
||||||
|
"Failed to create sous-traitant";
|
||||||
|
setError(errorMessage);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSousTraitant = async (payload: UpdateSousTraitantPayload) => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await SousTraitantService.updateSousTraitant(payload);
|
||||||
|
const updatedSousTraitant = response.data;
|
||||||
|
|
||||||
|
const index = sousTraitants.value.findIndex(
|
||||||
|
(item) => item.id === updatedSousTraitant.id
|
||||||
|
);
|
||||||
|
if (index !== -1) {
|
||||||
|
sousTraitants.value[index] = updatedSousTraitant;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentSousTraitant.value &&
|
||||||
|
currentSousTraitant.value.id === updatedSousTraitant.id
|
||||||
|
) {
|
||||||
|
setCurrentSousTraitant(updatedSousTraitant);
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedSousTraitant;
|
||||||
|
} catch (err: any) {
|
||||||
|
const errorMessage =
|
||||||
|
err.response?.data?.message ||
|
||||||
|
err.message ||
|
||||||
|
"Failed to update sous-traitant";
|
||||||
|
setError(errorMessage);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteSousTraitant = async (id: number) => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await SousTraitantService.deleteSousTraitant(id);
|
||||||
|
|
||||||
|
sousTraitants.value = sousTraitants.value.filter((item) => item.id !== id);
|
||||||
|
|
||||||
|
if (currentSousTraitant.value && currentSousTraitant.value.id === id) {
|
||||||
|
setCurrentSousTraitant(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (err: any) {
|
||||||
|
const errorMessage =
|
||||||
|
err.response?.data?.message ||
|
||||||
|
err.message ||
|
||||||
|
"Failed to delete sous-traitant";
|
||||||
|
setError(errorMessage);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchSousTraitants = async (
|
||||||
|
query: string,
|
||||||
|
exactMatch: boolean = false
|
||||||
|
) => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const results = await SousTraitantService.searchSousTraitants(query, {
|
||||||
|
exact_match: exactMatch,
|
||||||
|
});
|
||||||
|
setSearchResults(results);
|
||||||
|
return results;
|
||||||
|
} catch (err) {
|
||||||
|
setError("Erreur lors de la recherche des sous-traitants");
|
||||||
|
console.error("Error searching sous-traitants:", err);
|
||||||
|
setSearchResults([]);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearCurrentSousTraitant = () => {
|
||||||
|
setCurrentSousTraitant(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearStore = () => {
|
||||||
|
sousTraitants.value = [];
|
||||||
|
currentSousTraitant.value = null;
|
||||||
|
searchResults.value = [];
|
||||||
|
error.value = null;
|
||||||
|
pagination.value = {
|
||||||
|
current_page: 1,
|
||||||
|
last_page: 1,
|
||||||
|
per_page: 10,
|
||||||
|
total: 0,
|
||||||
|
from: 0,
|
||||||
|
to: 0,
|
||||||
|
};
|
||||||
|
filters.value = {
|
||||||
|
page: 1,
|
||||||
|
per_page: 10,
|
||||||
|
sort_by: "created_at",
|
||||||
|
sort_direction: "desc",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
sousTraitants,
|
||||||
|
currentSousTraitant,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
searchResults,
|
||||||
|
filters,
|
||||||
|
|
||||||
|
allSousTraitants,
|
||||||
|
activeSousTraitants,
|
||||||
|
inactiveSousTraitants,
|
||||||
|
evaluatingSousTraitants,
|
||||||
|
isLoading,
|
||||||
|
hasError,
|
||||||
|
getError,
|
||||||
|
getPagination,
|
||||||
|
getSousTraitantById,
|
||||||
|
|
||||||
|
fetchSousTraitants,
|
||||||
|
fetchSousTraitant,
|
||||||
|
createSousTraitant,
|
||||||
|
updateSousTraitant,
|
||||||
|
deleteSousTraitant,
|
||||||
|
searchSousTraitants,
|
||||||
|
clearCurrentSousTraitant,
|
||||||
|
clearStore,
|
||||||
|
clearError,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useSousTraitantStore;
|
||||||
Loading…
x
Reference in New Issue
Block a user