motorbike/app/Models/Products.php
andrymodeste fe80b9c4f8 fix: corrections et améliorations du 01-04-2026
## Recouvrement
- Liste triée par date décroissante
- Pop-up de confirmation anti-doublons
- Affichage avec permission "Voir" seule

## Mise à jour produit
- Correction erreur "Column count doesn't match" (triggers MySQL corrigés)
- Formulaire corrigé (action, catégorie, champs null)
- Catégorie et date d'arrivage correctement préremplis
- Historique affiche le nom de l'utilisateur qui modifie

## Espace commercial
- Colonne "Disponibilité" ajoutée avec statut "En attente de livraison"
- Bouton panier caché pour les motos commandées
- Surbrillance jaune pour les motos en attente

## Notifications
- Caissière reçoit les notifications via notifCommande
- notifSortieCaisse réservé à Direction/Admin

## Avances
- Colonne "N° Série" ajoutée dans toutes les listes
- Compteurs sur les boutons Incomplètes/Complètes

## Facture / BL
- Total, Remise, Total à payer affichés
- "Ariary" ne se répète plus
- Prix individuel par moto
- Impression automatique : 1 produit = Facture, 2+ = BL
- Remise multiple : colonne product changée en TEXT

## Rapports
- Filtre par date dans le rapport stock
- Filtre par commercial et mécanicien dans les performances
- Correction rapport stock (GROUP BY marque)
- Liens absolus (correction erreur 404)

## Sidebar
- Marge en haut supprimée (production)
- Padding en bas ajouté pour scroll complet

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:56:34 +02:00

268 lines
8.6 KiB
PHP

<?php
namespace App\Models;
use CodeIgniter\Model;
class Products extends Model
{
protected $table = 'products';
protected $primaryKey = 'id';
protected $allowedFields = ['name', 'sku', 'price', 'product_sold', 'qty', 'image', 'description', 'numero_de_moteur', 'marque', 'chasis', 'store_id', 'availability', 'is_piece', 'prix_vente', 'date_arivage', 'puissance', 'cler', 'categorie_id', 'etats','type', 'infoManquekit', 'info', 'infoManque'];
/**
* ✅ Récupérer les produits selon le rôle et le store de l'utilisateur
*/
public function getProductDataByRole(int $id = null)
{
$session = session();
$user = $session->get('user');
$isAdmin = in_array($user['group_name'], ['SuperAdmin', 'Direction', 'DAF']);
$builder = $this->where('is_piece', 0)
->whereIn('product_sold', [0, 2]);
if (!$isAdmin) {
if (empty($user['store_id']) || $user['store_id'] == 0) {
$builder->where('id', -1);
} else {
$builder->where('store_id', $user['store_id']);
}
}
if ($id) {
return $builder->where('id', $id)->first();
}
return $builder->orderBy('id', 'DESC')->findAll();
}
public function getProductData(int $id = null)
{
if ($id) {
return $this->where('id', $id)->first();
}
return $this->where([
'is_piece' => 0,
'product_sold' => 0
])->orderBy('id', 'DESC')->findAll();
}
public function getProductData2(int $id)
{
$builder = $this->where('is_piece', 0)
->where('product_sold', 0)
->where('store_id', $id);
return $builder->join('brands', 'brands.id = products.marque')
->orderBy('products.id', 'DESC')
->select('brands.name as brand_name, products.store_id as store_id, products.*')
->findAll();
}
public function getStockByBrand(int $id = 0)
{
$builder = $this->db->table('products')
->select('brands.name as brand_name, products.store_id, COUNT(*) as total_product')
->join('brands', 'brands.id = products.marque')
->where('products.is_piece', 0)
->where('products.product_sold', 0);
if ($id > 0) {
$builder->where('products.store_id', $id);
}
return $builder->groupBy('brands.name, products.store_id')
->orderBy('total_product', 'DESC')
->get()->getResultArray();
}
public function getProductData3(int $id)
{
if ($id == 0) {
return $this->where('is_piece', 0)->orderBy('id', 'DESC')->findAll();
}
return $this->where('is_piece', 0)->where('product_sold', 0)->where('store_id', $id)->orderBy('id', 'DESC')->findAll();
}
public function getProductDataStore(int $store_id, bool $excludeAvance = true, int $currentProductId = null)
{
$builder = $this->where('is_piece', 0)
->whereIn('product_sold', [0, 2])
->where('availability', 1)
->where('store_id', $store_id);
$db = \Config\Database::connect();
// Sous-requête pour exclure les produits en avance
if ($excludeAvance) {
$subQueryAvances = $db->table('avances')
->select('product_id')
->where('active', 1)
->where('is_order', 0)
->getCompiledSelect();
$builder->where("id NOT IN ($subQueryAvances)", null, false);
}
// ✅ LISTE : Exclure uniquement les produits dont la commande est LIVRÉE (paid_status = 3)
// Les produits commandés mais non livrés restent visibles dans les produits disponibles
$subQueryOrders = $db->table('orders_item')
->select('orders_item.product_id')
->join('orders', 'orders.id = orders_item.order_id')
->where('orders.paid_status', 3)
->getCompiledSelect();
$builder->where("id NOT IN ($subQueryOrders)", null, false);
// Exception pour le produit actuel lors de modification de commande
if ($currentProductId) {
$builder->orWhere('id', $currentProductId);
}
return $builder->orderBy('id', 'DESC')->findAll();
}
public function getActiveProductData()
{
return $this->where('is_piece', 0)->orderBy('id', 'DESC')->findAll();
}
public function assignToStore($productid = null, $storeid = null)
{
if (!is_null($productid) && !is_null($storeid)) {
$this->db->table('products')
->where('id', $productid)
->update(['store_id' => $storeid]);
return true;
}
return false;
}
public function create(array $data)
{
return $this->insert($data) ? true : false;
}
public function updateProduct(array $data, int $id)
{
return $this->update($id, $data) ? true : false;
}
public function remove(int $id)
{
return $this->delete($id) ? true : false;
}
/**
* ✅ NOUVELLE MÉTHODE : Compteur DASHBOARD (exclut uniquement statut 3)
* Utilisé pour afficher le nombre total de produits dans le dashboard
*/
public function countTotalProducts()
{
$db = \Config\Database::connect();
// Exclure produits en avance
$subQueryAvances = $db->table('avances')
->select('product_id')
->where('active', 1)
->where('is_order', 0)
->getCompiledSelect();
// ✅ Exclure UNIQUEMENT les produits avec statut 3 (livré)
$subQueryOrders = $db->table('orders_item')
->select('orders_item.product_id')
->join('orders', 'orders.id = orders_item.order_id')
->where('orders.paid_status', 3) // ✅ Décompté UNIQUEMENT quand livré
->getCompiledSelect();
return $this->where('is_piece', 0)
->where('product_sold', 0)
->where("id NOT IN ($subQueryAvances)", null, false)
->where("id NOT IN ($subQueryOrders)", null, false)
->countAllResults();
}
public function countAllProductsIncludingSold()
{
return $this->countAll();
}
public function getTotalProductPriceByIds(array $productIds)
{
try {
$total = 0.0;
foreach ($productIds as $id) {
$row = $this->select('price')
->where('id', $id)
->first();
if ($row && isset($row['price'])) {
$total += (float) $row['price'];
}
}
return $total;
} catch (\Throwable $th) {
return false;
}
}
public function getProductNameById(int $id): ?string
{
$product = $this->where('id', $id)->first();
if ($product && isset($product['name'])) {
return $product['name'];
}
return null;
}
/**
* ✅ NOUVELLE MÉTHODE : Compteur DASHBOARD par store (exclut uniquement statut 3)
* Compter les produits par store selon le rôle de l'utilisateur
*/
public function countProductsByUserStore()
{
$session = session();
$user = $session->get('user');
$isAdmin = in_array($user['group_name'], ['DAF', 'Direction', 'SuperAdmin']);
$db = \Config\Database::connect();
// Exclure avances
$subQueryAvances = $db->table('avances')
->select('product_id')
->where('active', 1)
->where('is_order', 0)
->getCompiledSelect();
// ✅ Exclure UNIQUEMENT les produits livrés (statut 3)
$subQueryOrders = $db->table('orders_item')
->select('orders_item.product_id')
->join('orders', 'orders.id = orders_item.order_id')
->where('orders.paid_status', 3) // ✅ Décompté UNIQUEMENT quand livré
->getCompiledSelect();
$builder = $this->where('is_piece', 0)
->where('product_sold', 0)
->where("id NOT IN ($subQueryAvances)", null, false)
->where("id NOT IN ($subQueryOrders)", null, false);
if (!$isAdmin && !empty($user['store_id']) && $user['store_id'] != 0) {
$builder->where('store_id', $user['store_id']);
} elseif (!$isAdmin) {
return 0;
}
return $builder->countAllResults();
}
}