mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-19 13:08:23 +02:00
6 files changed
+372
-184
No files matched your search
@@ -259,11 +259,11 @@ export default function BLReconciliation() {
|
|||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('Erreur vérification:', error);
|
console.error('Erreur vérification:', error);
|
||||||
toast({
|
toast({
|
||||||
title: "Erreur de vérification",
|
title: "Erreur de vérification",
|
||||||
description: "Impossible de vérifier la référence",
|
description: error.response?.data?.message || error.message || "Configuration NocoDB manquante ou incorrecte",
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
@@ -315,11 +315,11 @@ export default function BLReconciliation() {
|
|||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('Erreur recherche BL:', error);
|
console.error('Erreur recherche BL:', error);
|
||||||
toast({
|
toast({
|
||||||
title: "Erreur de recherche",
|
title: "Erreur de recherche",
|
||||||
description: "Impossible de rechercher par BL",
|
description: error.response?.data?.message || error.message || "Configuration NocoDB manquante ou incorrecte",
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1,212 +1,206 @@
|
|||||||
import { storage } from '../storage';
|
import { storage } from "../storage";
|
||||||
|
|
||||||
export interface InvoiceVerificationResult {
|
interface NocodbConfig {
|
||||||
found: boolean;
|
id: number;
|
||||||
invoiceReference?: string;
|
baseUrl: string;
|
||||||
invoiceAmount?: string;
|
apiToken: string;
|
||||||
supplierMatch: boolean;
|
projectId: string;
|
||||||
error?: string;
|
isActive: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BLSearchResult {
|
interface GroupConfig {
|
||||||
found: boolean;
|
nocodbConfigId?: number;
|
||||||
invoiceReference?: string;
|
nocodbTableName?: string;
|
||||||
invoiceAmount?: string;
|
invoiceColumnName?: string;
|
||||||
error?: string;
|
nocodbBlColumnName?: string;
|
||||||
|
nocodbAmountColumnName?: string;
|
||||||
|
nocodbSupplierColumnName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NocoDBVerificationService {
|
class NocodbVerificationService {
|
||||||
|
private async getNocodbConfig(configId: number): Promise<NocodbConfig | null> {
|
||||||
|
try {
|
||||||
|
return await storage.getNocodbConfig(configId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erreur récupération config NocoDB:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getGroupConfig(groupId: number): Promise<GroupConfig | null> {
|
||||||
|
try {
|
||||||
|
const group = await storage.getGroup(groupId);
|
||||||
|
if (!group) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
nocodbConfigId: group.nocodbConfigId || undefined,
|
||||||
|
nocodbTableName: group.nocodbTableName || undefined,
|
||||||
|
invoiceColumnName: group.invoiceColumnName || 'invoice_reference',
|
||||||
|
nocodbBlColumnName: group.nocodbBlColumnName || 'bl_number',
|
||||||
|
nocodbAmountColumnName: group.nocodbAmountColumnName || 'amount',
|
||||||
|
nocodbSupplierColumnName: group.nocodbSupplierColumnName || 'supplier'
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erreur récupération config groupe:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async makeNocodbRequest(
|
||||||
|
config: NocodbConfig,
|
||||||
|
tableName: string,
|
||||||
|
queryParams: Record<string, any>
|
||||||
|
): Promise<any> {
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
|
// Construire les filtres NocoDB
|
||||||
|
Object.entries(queryParams).forEach(([key, value]) => {
|
||||||
|
if (value !== undefined && value !== null) {
|
||||||
|
params.append(`where`, `(${key},eq,${value})`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const url = `${config.baseUrl}/api/v1/db/data/${config.projectId}/${tableName}?${params.toString()}`;
|
||||||
|
|
||||||
|
console.log('🔍 Requête NocoDB:', { url, table: tableName, filters: queryParams });
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'xc-auth': config.apiToken,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('✅ Réponse NocoDB:', { count: data.list?.length || 0 });
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Erreur requête NocoDB:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Vérifie l'existence d'une référence de facture dans NocoDB pour un magasin donné
|
|
||||||
*/
|
|
||||||
async verifyInvoiceReference(
|
async verifyInvoiceReference(
|
||||||
groupId: number,
|
groupId: number,
|
||||||
invoiceReference: string,
|
invoiceReference: string,
|
||||||
supplierName: string
|
supplierName: string
|
||||||
): Promise<InvoiceVerificationResult> {
|
): Promise<{ found: boolean; supplierMatch: boolean; data?: any }> {
|
||||||
try {
|
try {
|
||||||
console.log(`🔍 Vérification facture ${invoiceReference} pour fournisseur ${supplierName} (magasin ${groupId})`);
|
console.log('🔍 Vérification facture:', { groupId, invoiceReference, supplierName });
|
||||||
|
|
||||||
// Récupérer la configuration du magasin
|
// Récupérer la configuration du groupe
|
||||||
const group = await storage.getGroup(groupId);
|
const groupConfig = await this.getGroupConfig(groupId);
|
||||||
if (!group?.nocodbConfigId || !group.nocodbTableName) {
|
if (!groupConfig?.nocodbConfigId || !groupConfig?.nocodbTableName) {
|
||||||
console.log(`❌ Pas de configuration NocoDB pour le magasin ${groupId}`);
|
console.log('⚠️ Configuration NocoDB manquante pour le groupe', groupId);
|
||||||
return {
|
return { found: false, supplierMatch: false };
|
||||||
found: false,
|
|
||||||
supplierMatch: false,
|
|
||||||
error: 'Configuration NocoDB manquante pour ce magasin'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Récupérer la configuration NocoDB globale
|
// Récupérer la configuration NocoDB
|
||||||
const nocodbConfig = await storage.getNocodbConfig(group.nocodbConfigId);
|
const nocodbConfig = await this.getNocodbConfig(groupConfig.nocodbConfigId);
|
||||||
if (!nocodbConfig) {
|
if (!nocodbConfig || !nocodbConfig.isActive) {
|
||||||
return {
|
console.log('⚠️ Configuration NocoDB inactive ou manquante');
|
||||||
found: false,
|
return { found: false, supplierMatch: false };
|
||||||
supplierMatch: false,
|
|
||||||
error: 'Configuration NocoDB introuvable'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construire l'URL de l'API NocoDB
|
// Effectuer la recherche
|
||||||
const apiUrl = `${nocodbConfig.baseUrl}/api/v1/db/data/v1/${nocodbConfig.projectId}/${group.nocodbTableName}`;
|
const queryParams = {
|
||||||
|
[groupConfig.invoiceColumnName!]: invoiceReference
|
||||||
|
};
|
||||||
|
|
||||||
// Construire les paramètres de recherche
|
const response = await this.makeNocodbRequest(
|
||||||
const searchParams = new URLSearchParams();
|
nocodbConfig,
|
||||||
if (group.invoiceColumnName) {
|
groupConfig.nocodbTableName,
|
||||||
searchParams.append('where', `(${group.invoiceColumnName},eq,${invoiceReference})`);
|
queryParams
|
||||||
|
);
|
||||||
|
|
||||||
|
const records = response.list || response.rows || [];
|
||||||
|
|
||||||
|
if (records.length === 0) {
|
||||||
|
return { found: false, supplierMatch: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalUrl = `${apiUrl}?${searchParams.toString()}`;
|
// Vérifier la correspondance du fournisseur
|
||||||
console.log(`🌐 Requête NocoDB: ${finalUrl}`);
|
const record = records[0];
|
||||||
|
const recordSupplier = record[groupConfig.nocodbSupplierColumnName!];
|
||||||
|
|
||||||
// Faire la requête à NocoDB
|
const supplierMatch = recordSupplier &&
|
||||||
const response = await fetch(finalUrl, {
|
recordSupplier.toString().toLowerCase().includes(supplierName.toLowerCase());
|
||||||
headers: {
|
|
||||||
'xc-token': nocodbConfig.apiToken,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
console.error(`❌ Erreur NocoDB (${response.status}):`, await response.text());
|
|
||||||
return {
|
|
||||||
found: false,
|
|
||||||
supplierMatch: false,
|
|
||||||
error: `Erreur NocoDB: ${response.status}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
console.log(`📊 Réponse NocoDB:`, { found: data.list?.length > 0, count: data.list?.length });
|
|
||||||
|
|
||||||
if (data.list && data.list.length > 0) {
|
|
||||||
const record = data.list[0];
|
|
||||||
|
|
||||||
// Vérifier si le fournisseur correspond
|
|
||||||
let supplierMatch = true;
|
|
||||||
if (group.nocodbSupplierColumnName) {
|
|
||||||
const nocodbSupplier = record[group.nocodbSupplierColumnName];
|
|
||||||
supplierMatch = nocodbSupplier === supplierName;
|
|
||||||
console.log(`🏷️ Vérification fournisseur:`, {
|
|
||||||
expected: supplierName,
|
|
||||||
found: nocodbSupplier,
|
|
||||||
match: supplierMatch
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
found: true,
|
|
||||||
invoiceReference,
|
|
||||||
invoiceAmount: group.nocodbAmountColumnName ? record[group.nocodbAmountColumnName]?.toString() : undefined,
|
|
||||||
supplierMatch
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
found: false,
|
found: true,
|
||||||
supplierMatch: false
|
supplierMatch: !!supplierMatch,
|
||||||
|
data: record
|
||||||
};
|
};
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Erreur lors de la vérification facture:', error);
|
console.error('❌ Erreur vérification facture:', error);
|
||||||
return {
|
return { found: false, supplierMatch: false };
|
||||||
found: false,
|
|
||||||
supplierMatch: false,
|
|
||||||
error: `Erreur: ${error instanceof Error ? error.message : 'Erreur inconnue'}`
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Recherche une facture par numéro de BL et fournisseur
|
|
||||||
*/
|
|
||||||
async searchByBLNumber(
|
async searchByBLNumber(
|
||||||
groupId: number,
|
groupId: number,
|
||||||
blNumber: string,
|
blNumber: string,
|
||||||
supplierName: string
|
supplierName: string
|
||||||
): Promise<BLSearchResult> {
|
): Promise<{ found: boolean; invoiceReference?: string; invoiceAmount?: number; data?: any }> {
|
||||||
try {
|
try {
|
||||||
console.log(`🔍 Recherche par BL ${blNumber} pour fournisseur ${supplierName} (magasin ${groupId})`);
|
console.log('🔍 Recherche par BL:', { groupId, blNumber, supplierName });
|
||||||
|
|
||||||
// Récupérer la configuration du magasin
|
// Récupérer la configuration du groupe
|
||||||
const group = await storage.getGroup(groupId);
|
const groupConfig = await this.getGroupConfig(groupId);
|
||||||
if (!group?.nocodbConfigId || !group.nocodbTableName || !group.nocodbBlColumnName) {
|
if (!groupConfig?.nocodbConfigId || !groupConfig?.nocodbTableName) {
|
||||||
console.log(`❌ Configuration BL manquante pour le magasin ${groupId}`);
|
console.log('⚠️ Configuration NocoDB manquante pour le groupe', groupId);
|
||||||
return {
|
return { found: false };
|
||||||
found: false,
|
|
||||||
error: 'Configuration NocoDB pour recherche BL manquante'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Récupérer la configuration NocoDB globale
|
// Récupérer la configuration NocoDB
|
||||||
const nocodbConfig = await storage.getNocodbConfig(group.nocodbConfigId);
|
const nocodbConfig = await this.getNocodbConfig(groupConfig.nocodbConfigId);
|
||||||
if (!nocodbConfig) {
|
if (!nocodbConfig || !nocodbConfig.isActive) {
|
||||||
return {
|
console.log('⚠️ Configuration NocoDB inactive ou manquante');
|
||||||
found: false,
|
return { found: false };
|
||||||
error: 'Configuration NocoDB introuvable'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construire l'URL de l'API NocoDB pour recherche par BL
|
// Effectuer la recherche par BL
|
||||||
const apiUrl = `${nocodbConfig.baseUrl}/api/v1/db/data/v1/${nocodbConfig.projectId}/${group.nocodbTableName}`;
|
const queryParams = {
|
||||||
|
[groupConfig.nocodbBlColumnName!]: blNumber,
|
||||||
|
[groupConfig.nocodbSupplierColumnName!]: supplierName
|
||||||
|
};
|
||||||
|
|
||||||
// Construire les paramètres de recherche par BL et éventuellement fournisseur
|
const response = await this.makeNocodbRequest(
|
||||||
const searchParams = new URLSearchParams();
|
nocodbConfig,
|
||||||
let whereClause = `(${group.nocodbBlColumnName},eq,${blNumber})`;
|
groupConfig.nocodbTableName,
|
||||||
|
queryParams
|
||||||
|
);
|
||||||
|
|
||||||
// Ajouter la condition fournisseur si configurée
|
const records = response.list || response.rows || [];
|
||||||
if (group.nocodbSupplierColumnName) {
|
|
||||||
whereClause += `~and(${group.nocodbSupplierColumnName},eq,${supplierName})`;
|
if (records.length === 0) {
|
||||||
|
return { found: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
searchParams.append('where', whereClause);
|
const record = records[0];
|
||||||
|
const invoiceReference = record[groupConfig.invoiceColumnName!];
|
||||||
const finalUrl = `${apiUrl}?${searchParams.toString()}`;
|
const invoiceAmount = record[groupConfig.nocodbAmountColumnName!];
|
||||||
console.log(`🌐 Requête NocoDB recherche BL: ${finalUrl}`);
|
|
||||||
|
|
||||||
// Faire la requête à NocoDB
|
|
||||||
const response = await fetch(finalUrl, {
|
|
||||||
headers: {
|
|
||||||
'xc-token': nocodbConfig.apiToken,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
console.error(`❌ Erreur NocoDB recherche BL (${response.status}):`, await response.text());
|
|
||||||
return {
|
|
||||||
found: false,
|
|
||||||
error: `Erreur NocoDB: ${response.status}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
console.log(`📊 Réponse NocoDB recherche BL:`, { found: data.list?.length > 0, count: data.list?.length });
|
|
||||||
|
|
||||||
if (data.list && data.list.length > 0) {
|
|
||||||
const record = data.list[0];
|
|
||||||
|
|
||||||
return {
|
|
||||||
found: true,
|
|
||||||
invoiceReference: group.invoiceColumnName ? record[group.invoiceColumnName] : undefined,
|
|
||||||
invoiceAmount: group.nocodbAmountColumnName ? record[group.nocodbAmountColumnName]?.toString() : undefined
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
found: false
|
found: true,
|
||||||
|
invoiceReference: invoiceReference?.toString(),
|
||||||
|
invoiceAmount: invoiceAmount ? parseFloat(invoiceAmount.toString()) : undefined,
|
||||||
|
data: record
|
||||||
};
|
};
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Erreur lors de la recherche par BL:', error);
|
console.error('❌ Erreur recherche par BL:', error);
|
||||||
return {
|
return { found: false };
|
||||||
found: false,
|
|
||||||
error: `Erreur: ${error instanceof Error ? error.message : 'Erreur inconnue'}`
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const nocodbVerificationService = new NocoDBVerificationService();
|
export const nocodbVerificationService = new NocodbVerificationService();
|
||||||
+20
-13
@@ -1073,19 +1073,26 @@ export class DatabaseStorage implements IStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getNocodbConfig(id: number): Promise<NocodbConfig | undefined> {
|
async getNocodbConfig(id: number): Promise<NocodbConfig | undefined> {
|
||||||
const configs = await db.select({
|
try {
|
||||||
id: nocodbConfig.id,
|
const configs = await db.select({
|
||||||
name: nocodbConfig.name,
|
id: nocodbConfig.id,
|
||||||
baseUrl: nocodbConfig.baseUrl,
|
name: nocodbConfig.name,
|
||||||
projectId: nocodbConfig.projectId,
|
baseUrl: nocodbConfig.baseUrl,
|
||||||
apiToken: nocodbConfig.apiToken,
|
projectId: nocodbConfig.projectId,
|
||||||
description: nocodbConfig.description,
|
apiToken: nocodbConfig.apiToken,
|
||||||
isActive: nocodbConfig.isActive,
|
description: nocodbConfig.description,
|
||||||
createdBy: nocodbConfig.createdBy,
|
isActive: nocodbConfig.isActive,
|
||||||
createdAt: nocodbConfig.createdAt,
|
createdBy: nocodbConfig.createdBy,
|
||||||
updatedAt: nocodbConfig.updatedAt,
|
createdAt: nocodbConfig.createdAt,
|
||||||
}).from(nocodbConfig).where(eq(nocodbConfig.id, id));
|
updatedAt: nocodbConfig.updatedAt,
|
||||||
return configs[0];
|
}).from(nocodbConfig).where(eq(nocodbConfig.id, id));
|
||||||
|
|
||||||
|
console.log(`🔍 Production NocoDB Config Query - ID: ${id}, Found: ${configs.length > 0}`);
|
||||||
|
return configs[0];
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Erreur récupération config NocoDB ${id}:`, error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async createNocodbConfig(config: InsertNocodbConfig): Promise<NocodbConfig> {
|
async createNocodbConfig(config: InsertNocodbConfig): Promise<NocodbConfig> {
|
||||||
|
|||||||
+6
-6
@@ -143,16 +143,16 @@ export const publicityParticipations = pgTable("publicity_participations", {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// NocoDB configuration globale (une seule instance NocoDB partagée)
|
// NocoDB configuration globale - Structure correspondant à la production
|
||||||
export const nocodbConfig = pgTable("nocodb_config", {
|
export const nocodbConfig = pgTable("nocodb_config", {
|
||||||
id: serial("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
name: varchar("name").notNull(), // Nom de la configuration
|
name: varchar("name", { length: 255 }).notNull(), // Nom de la configuration
|
||||||
baseUrl: varchar("base_url").notNull(), // URL de l'instance NocoDB
|
baseUrl: varchar("base_url", { length: 255 }).notNull(), // URL de l'instance NocoDB
|
||||||
projectId: varchar("project_id").notNull(), // NocoDB Project ID
|
projectId: varchar("project_id", { length: 255 }).notNull(), // NocoDB Project ID
|
||||||
apiToken: varchar("api_token").notNull(), // Personal API Token
|
apiToken: varchar("api_token", { length: 255 }).notNull(), // Personal API Token
|
||||||
description: text("description"), // Description de la configuration
|
description: text("description"), // Description de la configuration
|
||||||
isActive: boolean("is_active").default(true), // Configuration active ou non
|
isActive: boolean("is_active").default(true), // Configuration active ou non
|
||||||
createdBy: varchar("created_by").notNull(),
|
createdBy: varchar("created_by", { length: 255 }), // Créateur (nullable en production)
|
||||||
createdAt: timestamp("created_at").defaultNow(),
|
createdAt: timestamp("created_at").defaultNow(),
|
||||||
updatedAt: timestamp("updated_at").defaultNow(),
|
updatedAt: timestamp("updated_at").defaultNow(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
# Guide Complet - Configuration NocoDB Production
|
||||||
|
|
||||||
|
## ❌ PROBLÈME IDENTIFIÉ
|
||||||
|
|
||||||
|
Votre serveur de production n'a **aucune configuration NocoDB** dans la base de données. C'est pourquoi vous ne voyez rien.
|
||||||
|
|
||||||
|
## ✅ SOLUTION : Configuration Complète
|
||||||
|
|
||||||
|
### Étape 1 : Ajout Configuration NocoDB
|
||||||
|
|
||||||
|
Connectez-vous à votre base PostgreSQL de production et exécutez :
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 1. Vérifier si la table existe
|
||||||
|
\d nocodb_config
|
||||||
|
|
||||||
|
-- 2. Insérer votre configuration NocoDB
|
||||||
|
INSERT INTO nocodb_config (
|
||||||
|
name,
|
||||||
|
base_url,
|
||||||
|
project_id,
|
||||||
|
api_token,
|
||||||
|
description,
|
||||||
|
is_active
|
||||||
|
) VALUES (
|
||||||
|
'Production Principal',
|
||||||
|
'https://app.nocodb.com', -- ou votre URL NocoDB
|
||||||
|
'VOTRE_PROJECT_ID', -- À remplacer
|
||||||
|
'VOTRE_API_TOKEN', -- À remplacer
|
||||||
|
'Configuration principale pour vérification automatique factures',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 3. Vérifier l'insertion
|
||||||
|
SELECT * FROM nocodb_config;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 2 : Configuration des Magasins
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Lister vos magasins existants
|
||||||
|
SELECT id, name FROM groups;
|
||||||
|
|
||||||
|
-- Configurer chaque magasin (exemple pour ID 1)
|
||||||
|
UPDATE groups SET
|
||||||
|
nocodb_config_id = 1, -- ID de la config créée
|
||||||
|
nocodb_table_name = 'VOTRE_TABLE_FACTURES', -- Nom réel de votre table NocoDB
|
||||||
|
invoice_column_name = 'reference_facture', -- Colonne référence
|
||||||
|
nocodb_bl_column_name = 'numero_bl', -- Colonne BL
|
||||||
|
nocodb_amount_column_name = 'montant', -- Colonne montant
|
||||||
|
nocodb_supplier_column_name = 'fournisseur' -- Colonne fournisseur
|
||||||
|
WHERE id = 1; -- Remplacer par l'ID réel
|
||||||
|
|
||||||
|
-- Répéter pour chaque magasin avec ses propres paramètres
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 3 : Obtenir les Informations NocoDB
|
||||||
|
|
||||||
|
1. **Project ID** : Dans NocoDB, aller dans Project Settings
|
||||||
|
2. **API Token** : Account Settings > Tokens > Create new token
|
||||||
|
3. **Table Names** : Noter les noms exacts de vos tables
|
||||||
|
4. **Column Names** : Noter les noms exacts de vos colonnes
|
||||||
|
|
||||||
|
### Étape 4 : Test de Configuration
|
||||||
|
|
||||||
|
Une fois configuré, redémarrez votre serveur et vous devriez voir :
|
||||||
|
- Boutons loupe et coche dans le rapprochement
|
||||||
|
- Logs de débogage dans la console serveur
|
||||||
|
- Notifications de succès/erreur
|
||||||
|
|
||||||
|
### Étape 5 : Vérification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Voir toutes les configurations
|
||||||
|
SELECT
|
||||||
|
g.id,
|
||||||
|
g.name as magasin,
|
||||||
|
g.nocodb_config_id,
|
||||||
|
g.nocodb_table_name,
|
||||||
|
g.invoice_column_name,
|
||||||
|
nc.base_url,
|
||||||
|
nc.is_active
|
||||||
|
FROM groups g
|
||||||
|
LEFT JOIN nocodb_config nc ON g.nocodb_config_id = nc.id;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 Structure Attendue de vos Tables NocoDB
|
||||||
|
|
||||||
|
Chaque table de factures doit contenir au minimum :
|
||||||
|
- **Référence Facture** (ex: FAC-2024-001)
|
||||||
|
- **Numéro BL** (ex: BL123456)
|
||||||
|
- **Montant** (ex: 150.75)
|
||||||
|
- **Fournisseur** (ex: "Fournisseur ABC")
|
||||||
|
|
||||||
|
## 🚨 Points Critiques
|
||||||
|
|
||||||
|
1. **API Token** : Doit avoir accès lecture à vos tables
|
||||||
|
2. **Noms Exacts** : Table/colonne names doivent être exacts (sensible à la casse)
|
||||||
|
3. **Données Test** : Ayez quelques factures test dans NocoDB
|
||||||
|
4. **Connexion** : Vérifiez que votre serveur peut accéder à NocoDB
|
||||||
|
|
||||||
|
## 📞 Support
|
||||||
|
|
||||||
|
Si ça ne marche toujours pas après configuration :
|
||||||
|
1. Vérifiez les logs serveur Node.js
|
||||||
|
2. Testez l'API NocoDB manuellement avec curl
|
||||||
|
3. Confirmez que les noms de colonnes sont corrects
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# Configuration NocoDB pour Production
|
||||||
|
|
||||||
|
## 1. Configuration de la base de données
|
||||||
|
|
||||||
|
Votre table `nocodb_config` existe déjà. Vous devez y ajouter une configuration :
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Insertion d'une configuration NocoDB de base
|
||||||
|
INSERT INTO nocodb_config (
|
||||||
|
name,
|
||||||
|
base_url,
|
||||||
|
project_id,
|
||||||
|
api_token,
|
||||||
|
description,
|
||||||
|
is_active,
|
||||||
|
created_by,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
) VALUES (
|
||||||
|
'Configuration Principale',
|
||||||
|
'https://votre-nocodb.domain.com',
|
||||||
|
'votre-project-id',
|
||||||
|
'votre-api-token-personnel',
|
||||||
|
'Configuration principale pour vérification factures',
|
||||||
|
true,
|
||||||
|
'admin',
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configuration des groupes (magasins)
|
||||||
|
|
||||||
|
Mettez à jour vos magasins avec les configurations NocoDB :
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Exemple pour Magasin A
|
||||||
|
UPDATE groups SET
|
||||||
|
nocodb_config_id = 1, -- ID de la config NocoDB créée ci-dessus
|
||||||
|
nocodb_table_name = 'nom_table_factures_magasin_a', -- Nom de votre table NocoDB
|
||||||
|
invoice_column_name = 'reference_facture', -- Colonne référence facture
|
||||||
|
nocodb_bl_column_name = 'numero_bl', -- Colonne numéro BL
|
||||||
|
nocodb_amount_column_name = 'montant', -- Colonne montant
|
||||||
|
nocodb_supplier_column_name = 'fournisseur' -- Colonne fournisseur
|
||||||
|
WHERE id = 1; -- Remplacer par l'ID de votre magasin
|
||||||
|
|
||||||
|
-- Répéter pour chaque magasin avec ses propres noms de table/colonnes
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. API Token NocoDB
|
||||||
|
|
||||||
|
Pour obtenir votre API Token :
|
||||||
|
1. Allez dans NocoDB > Account Settings > Tokens
|
||||||
|
2. Créez un nouveau Personal API Token
|
||||||
|
3. Copiez le token dans la configuration ci-dessus
|
||||||
|
|
||||||
|
## 4. Structure de votre table NocoDB
|
||||||
|
|
||||||
|
Assurez-vous que vos tables NocoDB contiennent ces colonnes :
|
||||||
|
- Référence facture (ex: `reference_facture`)
|
||||||
|
- Numéro BL (ex: `numero_bl`)
|
||||||
|
- Montant (ex: `montant`)
|
||||||
|
- Fournisseur (ex: `fournisseur`)
|
||||||
|
|
||||||
|
## 5. Test de la configuration
|
||||||
|
|
||||||
|
Une fois configuré, le système :
|
||||||
|
- ✅ Affichera des boutons de vérification dans le rapprochement BL/Factures
|
||||||
|
- ✅ Vérifiera automatiquement les références factures existantes
|
||||||
|
- ✅ Auto-remplira les champs manquants en recherchant par BL
|
||||||
|
- ✅ Affichera des coches vertes pour les factures vérifiées
|
||||||
|
|
||||||
|
## 6. Débogage
|
||||||
|
|
||||||
|
Les logs de production afficheront :
|
||||||
|
```
|
||||||
|
🔍 Vérification facture: {groupId: 1, invoiceReference: "FAC123", supplierName: "Fournisseur A"}
|
||||||
|
🌐 Requête NocoDB: https://votre-nocodb.domain.com/api/v1/db/data/project-id/table-name?where=...
|
||||||
|
✅ Réponse NocoDB: {count: 1}
|
||||||
|
```
|
||||||
Reference in new issue
Block a user