Gestione Punti Vendita (Outlets) con Cassa in Cloud
Panoramica
Il sistema di gestione punti vendita (Outlets) è integrato con Cassa in Cloud per sincronizzare automaticamente i dati dei punti vendita e utilizzarli in tutte le funzionalità dell’applicazione.
Architettura
Modello Database
Il modello Outlet include:
- Multi-tenant: Ogni outlet è associato a un
tenant_id - Integrazione Cassa in Cloud: Campo
cassaincloud_idper identificare il punto vendita su Cassa in Cloud - Sincronizzazione: Campo
lastSyncAtper tracciare l’ultima sincronizzazione - Dati completi: Informazioni su indirizzo, orari di apertura, social media, ecc.
{
_id: ObjectId,
cassaincloud_id: string, // ID da Cassa in Cloud
tenant_id: ObjectId,
name: string,
address: {
street: string,
city: string,
province: string,
postalCode: string,
country: string,
coordinates: { latitude, longitude }
},
isActive: boolean,
isPrimary: boolean, // Punto vendita principale
lastSyncAt: Date
}API Endpoints
1. Sincronizzazione da Cassa in Cloud
POST /api/outlets/sync
Sincronizza i punti vendita da Cassa in Cloud al database locale.
Body:
{
"salesPoints": [
{
"id": "123",
"description": "Punto Vendita Centro",
"address": "Via Roma 1",
"city": "Milano",
"country": "Italia"
}
]
}Risposta:
{
"success": true,
"results": {
"created": 2,
"updated": 1,
"errors": []
}
}2. Ottenere tutti gli outlets
GET /api/outlets
Restituisce tutti i punti vendita del tenant corrente.
3. CRUD Operations
- POST
/api/outlets- Crea un nuovo outlet - PUT
/api/outlets- Aggiorna un outlet esistente - DELETE
/api/outlets?id=xxx- Elimina un outlet
Redux API
Hook disponibili
import {
useGetOutletsQuery,
useGetOutletQuery,
useCreateOutletMutation,
useUpdateOutletMutation,
useDeleteOutletMutation,
useSyncOutletsMutation,
} from "@/store/api/outletsApi";Esempio d’uso
function MyComponent() {
const { data: outlets, isLoading } = useGetOutletsQuery();
const [syncOutlets, { isLoading: isSyncing }] = useSyncOutletsMutation();
// Ottieni punti vendita da Cassa in Cloud
const { data: salesPoints } = useGetSalesPointsQuery({
hasActiveLicense: true,
});
// Sincronizza
const handleSync = async () => {
await syncOutlets({
salesPoints: salesPoints.salesPoint,
});
};
return (
<div>
{outlets?.map(outlet => (
<div key={outlet._id}>{outlet.name}</div>
))}
</div>
);
}Componenti UI
1. SyncOutletsButton
Pulsante per sincronizzare i punti vendita da Cassa in Cloud.
import { SyncOutletsButton } from "@/components/outlets/SyncOutletsButton";
<SyncOutletsButton />;2. OutletSelector
Dropdown per selezionare un punto vendita.
import { OutletSelector } from "@/components/outlets/OutletSelector";
function MyForm() {
const [selectedOutlet, setSelectedOutlet] = useState("");
return (
<OutletSelector
value={selectedOutlet}
onValueChange={setSelectedOutlet}
allowAll={true} // Permette "Tutti i punti vendita"
/>
);
}Utilizzo nelle API
Molte API supportano il filtro per punto vendita. Quando si chiamano le API di Cassa in Cloud, usare idsSalesPoint:
// Ottenere prodotti filtrati per punto vendita
const { data } = useGetProductsQuery({
idsSalesPoint: [123, 456], // Array di ID punti vendita
limit: 100,
});
// Ottenere vendite filtrate per punto vendita
const { data } = useGetSalesByProductQuery({
idsSalesPoint: [123],
dateFrom: "2024-01-01",
dateTo: "2024-12-31",
});Flusso di Sincronizzazione
- L’utente clicca su “Sincronizza Punti Vendita”
- Il componente chiama
useGetSalesPointsQuery()per ottenere i punti vendita da Cassa in Cloud - Viene chiamato
useSyncOutletsMutation()con i dati ricevuti - L’API
/api/outlets/syncprocessa i dati:- Cerca outlet esistenti con lo stesso
cassaincloud_id - Se esiste, aggiorna i dati
- Se non esiste, crea un nuovo outlet
- Cerca outlet esistenti con lo stesso
- Tutti gli outlet sono associati al
tenant_iddell’utente corrente - Il componente mostra il risultato della sincronizzazione
Migrazione Dati Esistenti
Se hai già outlet nel database senza cassaincloud_id, puoi aggiungerlo manualmente o tramite uno script:
// Script di migrazione
const outlets = await Outlet.find({ cassaincloud_id: { $exists: false } });
for (const outlet of outlets) {
// Cerca corrispondenza su Cassa in Cloud per nome/indirizzo
const salesPoint = await findMatchingSalesPoint(outlet);
if (salesPoint) {
outlet.cassaincloud_id = salesPoint.id;
await outlet.save();
}
}Best Practices
- Sincronizzazione regolare: Esegui la sincronizzazione ogni settimana per mantenere i dati aggiornati
- Punto vendita principale: Imposta
isPrimary: trueper il punto vendita principale - Filtri nelle query: Usa sempre gli outlet per filtrare i dati quando necessario
- Validazione: Verifica sempre che l’outlet selezionato appartenga al tenant corrente
Integrazione con altre feature
Reports
Filtra i report per punto vendita:
<OutletSelector
value={selectedOutlet}
onValueChange={setSelectedOutlet}
/>
<SalesReport outletId={selectedOutlet} />Inventory
Gestisci l’inventario per punto vendita:
const { data: inventory } = useGetInventoryQuery({
outlet_id: selectedOutlet,
});Fatture
Filtra le fatture per punto vendita di destinazione.
Troubleshooting
Problema: Nessun punto vendita disponibile
Soluzione:
- Verifica che l’API key di Cassa in Cloud sia configurata correttamente in
.env.local - Verifica che l’account Cassa in Cloud abbia punti vendita attivi
- Esegui la sincronizzazione manualmente
Problema: Duplicati dopo la sincronizzazione
Soluzione: La sincronizzazione usa cassaincloud_id per prevenire duplicati. Se hai duplicati, uno degli outlet non ha cassaincloud_id impostato correttamente.
Problema: Punti vendita non visibili nelle API
Soluzione: Verifica che il tenant_id sia corretto e che l’utente sia autenticato.