motorbike/app/Controllers/ProductCOntroller.php
2025-07-08 16:43:45 +02:00

589 lines
23 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Controllers;
use App\Models\Attributes;
use App\Models\Brands;
use App\Models\Category;
use App\Models\FourchettePrix;
use App\Models\Notification;
use App\Models\Products;
use App\Models\Stores;
use Config\Services;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
class ProductCOntroller extends AdminController
{
public function __construct()
{
parent::__construct();
// Assuming permission is being set from a session
helper(['form', 'url']);
}
private $pageTitle = 'Produits';
public function index()
{
$Stores = new Stores();
$this->verifyRole('viewProduct');
$data['page_title'] = $this->pageTitle;
$Product = new Products();
$data['motos'] = $Product->getActiveProductData();
$data['stores'] = $Stores->getActiveStore();
return $this->render_template('products/index', $data);
}
public function assign_store()
{
// Vérifie que la requête est bien une requête AJAX
if (!$this->request->isAJAX()) {
$response = Services::response();
$response->setStatusCode(404, 'Page Not Found')->send();
exit;
}
// Récupère les données POST sous format JSON
$data = $this->request->getJSON(true); // Décodage en tableau associatif
if (!isset($data['product_id']) || !isset($data['store_id'])) {
return $this->response->setJSON([
'success' => false,
'message' => 'Paramètres manquants.'
])->setStatusCode(400);
}
$product_id = $data['product_id'];
$store_id = $data['store_id'];
$productsModel = new Products();
// Appeler la méthode assignToStore pour mettre à jour la base de données
$result = $productsModel->assignToStore($product_id, $store_id);
// Répondre en JSON avec le résultat
if ($result) {
return $this->response->setJSON(['success' => true]);
} else {
return $this->response->setJSON(['success' => false, 'message' => 'Échec de la mise à jour.']);
}
}
public function fetchProductData()
{
// Initialize the response array
$result = ['data' => []];
$Products = new Products();
$Stores = new Stores();
function convertString($name)
{
return "$name";
}
// Fetch product data from the model
$data = $Products->getProductData(); // Ensure this method exists in your ProductModel
foreach ($data as $key => $value) {
// Fetch store data
$store_data = $Stores->getStoresData($value['store_id']); // Ensure this method exists in your StoreModel
$store_data['name'] = $value['store_id'] == 0 ? "TOUS" : $Stores->getStoresData($value['store_id'])["name"];
// Construct buttons
$buttons = '';
if (in_array('updateProduct', $this->permission ?? [])) {
$buttons .= '<a href="' . base_url('products/update/' . $value['id']) . '" class="btn btn-default"><i class="fa fa-pencil"></i></a>';
}
if (in_array('deleteProduct', $this->permission ?? [])) {
$buttons .= ' <button type="button" class="btn btn-danger" onclick="removeFunc(' . $value['id'] . ')" data-toggle="modal" data-target="#removeModal"><i class="fa fa-trash"></i></button>';
}
if (in_array('updateProduct', $this->permission ?? [])) {
$buttons .= ' <a href="ventes/' . $value['id'] . '" class="btn btn-default"><i class="fa fa-image"></i></a>';
}
if (in_array('updateProduct', $this->permission ?? [])) {
$buttons .= ' <button class="btn btn-default" onclick="generateQrPdf(' . $value["id"] . ')"><i class="fa fa-qrcode"></i></button>';
}
if (in_array('viewProduct', $this->permission ?? [])) {
$buttons .= " <a href='/ventes/show/" . $value['id'] . "' class='btn btn-default'><i class='fa fa-eye'></i></a>";
}
if (in_array('assignStore', $this->permission ?? [])) {
$buttons .=
'<button type="button" class="btn btn-info assignbtn" title="Assigner sur un magasin" data-magasin="' . $store_data['name'] . '" data-products-id="' . $value["id"] . '" data-toggle="modal" data-target="#assignStoreModal">
<i class="fa fa-forward"></i>
</button>';
}
// Image HTML
$img = '<img src="' . base_url('assets/images/product_image/' . $value['image']) . '" alt="' . $value['name'] . '" class="img-circle" width="50" height="50" />';
// Availability Status
$availability = ($value['availability'] == 1) ? '<span class="label label-success">Disponible</span>' : '<span class="label label-warning">Indisponible</span>';
// Quantity Status
$qty_status = '';
if ($value['qty'] <= 10 && $value['qty'] > 0) {
$qty_status = '<span class="label label-warning">Low!</span>';
} elseif ($value['product_sold'] == false) {
$qty_status = '<span class="label label-danger">Rupture de stock!</span>';
}
// Populate the result data
$result['data'][] = [
$img,
$value['sku'],
$value['name'],
number_format($value['prix_vente'], 0, ',', ' '),
$store_data['name'] ?? 'Unknown Store',
$availability,
$buttons
];
}
// Return JSON response
return $this->response->setJSON($result);
}
public function create()
{
$Products = new Products();
$Brands = new Brands();
$Category = new Category();
$Stores = new Stores();
$Notification = new NotificationController();
$this->verifyRole('createProduct');
$data['page_title'] = $this->pageTitle;
// die(var_dump(json_encode($this->request->getPost('categorie[]'))));
// Validate form inputs
$validation = \Config\Services::validation();
$validation->setRules([
'nom_de_produit' => 'required',
'marque' => 'required',
'numero_de_moteur' => 'required',
'prix' => 'required|numeric',
'price_vente' => 'required|numeric',
'puissance' => 'required',
'store' => 'required',
'availability' => 'required',
'price_min' => 'required|numeric',
]);
if ($this->request->getMethod() === 'post' && $validation->withRequest($this->request)->run()) {
// die(var_dump($this->request->getPost()));
// Handle image upload
$upload_image = $this->uploadImage();
// Prepare data for insertion
$product_sold = false;
$data = [
'name' => $this->request->getPost('nom_de_produit'),
'sku' => $this->request->getPost('numero_de_serie'),
'price' => $this->request->getPost('prix'),
'qty' => 1,
'image' => $upload_image,
'description' => $this->request->getPost('description'),
'numero_de_moteur' => $this->request->getPost('numero_de_moteur'),
'marque' => $this->request->getPost('marque'),
'chasis' => $this->request->getPost('chasis'),
'store_id' => $this->request->getPost('store'),
'availability' => $this->request->getPost('availability'),
'prix_vente' => $this->request->getPost('price_vente'),
'date_arivage' => $this->request->getPost('datea'),
'puissance' => $this->request->getPost('puissance'),
'cler' => $this->request->getPost('cler'),
'categorie_id' => json_encode($this->request->getPost('categorie[]')),
'etats' => $this->request->getPost('etats'),
'infoManquekit' => $this->request->getPost('infoManquekit'),
'info' => $this->request->getPost('info'),
'infoManque' => $this->request->getPost('infoManque'),
'product_sold' => $product_sold,
];
$store_id1 = (int)$this->request->getPost('store');
// Insert data into the database
if ($Products->create($data)) {
$data = [
'product_id' => $Products->insertID(),
'prix_minimal' => $this->request->getPost('price_min'),
];
$Fourchette = new FourchettePrix();
$Fourchette->createFourchettePrix($data);
session()->setFlashdata('success', 'Créé avec succès');
$Notification->createNotification("Un nouveau Produit a été crée", "COMMERCIALE",$store_id1,'product/');
return redirect()->to('/products');
} else {
session()->setFlashdata('errors', 'Error occurred while creating the product');
return redirect()->to('products/create');
}
} else {
$data = [
'stores' => $Stores->getActiveStore(),
'validation' => $validation, // Pass validation errors to the view
'page_title' => $this->pageTitle,
'marque' => $Brands->getActiveBrands(),
'categorie' => $Category->getActiveCategory(),
];
// Render the form view
return $this->render_template('products/create', $data);
}
}
private function uploadImage()
{
// Define the upload directory
$uploadPath = 'assets/images/product_image';
// Ensure the directory exists
if (!is_dir($uploadPath)) {
mkdir($uploadPath, 0777, true);
}
// Check if the file is uploaded via the form
$file = $this->request->getFile('product_image');
if ($file && $file->isValid() && !$file->hasMoved()) {
// Generate a unique file name
$newName = uniqid() . '.' . $file->getExtension();
// Move the file to the target directory
$file->move($uploadPath, $newName);
// Return the actual file name
return $newName;
}
// If an error occurs, return the error message
return $file ? $file->getErrorString() : 'No file was uploaded.';
}
public function update(int $id)
{
$Products = new Products();
$Stores = new Stores();
$Category = new Category();
$this->verifyRole('updateProduct');
$data['page_title'] = $this->pageTitle;
$Brands = new Brands();
// Validate form inputs
$validation = \Config\Services::validation();
$validation->setRules([
'nom_de_produit' => 'required',
'marque' => 'required',
]);
if ($this->request->getMethod() === 'post' && $validation->withRequest($this->request)->run()) {
$data = [
'name' => $this->request->getPost('nom_de_produit'),
'sku' => $this->request->getPost('numero_de_serie'),
'price' => $this->request->getPost('price'),
'qty' => 1,
'description' => $this->request->getPost('description'),
'numero_de_moteur' => $this->request->getPost('numero_de_moteur'),
'marque' => $this->request->getPost('marque'),
'chasis' => $this->request->getPost('chasis'),
'store_id' => $this->request->getPost('store'),
'availability' => $this->request->getPost('availability'),
'prix_vente' => $this->request->getPost('price_vente'),
'date_arivage' => $this->request->getPost('datea'),
'puissance' => $this->request->getPost('puissance'),
'cler' => $this->request->getPost('cler'),
'categorie_id' => json_encode($this->request->getPost('categorie[]')),
'etats' => $this->request->getPost('etats'),
'infoManquekit' => $this->request->getPost('infoManquekit'),
'info' => $this->request->getPost('info'),
'infoManque' => $this->request->getPost('infoManque'),
];
// Check if a product image is uploaded
if ($this->request->getFile('product_image')->isValid()) {
$uploadImage = $this->uploadImage(); // Use the previously provided upload function
$uploadData = ['image' => $uploadImage];
// Update the product with the uploaded image
$Products->update($id, $uploadData);
}
if ($Products->updateProduct($data, $id)) {
// die(var_dump('tonga eto'));
session()->setFlashdata('success', 'Successfully updated');
return redirect()->to('/products');
} else {
session()->setFlashdata('errors', 'Error occurred!!');
return redirect()->to('/produtcs/update/' . $id);
}
} else {
$data = [
'stores' => $Stores->getActiveStore(),
'validation' => $validation, // Pass validation errors to the view
'page_title' => $this->pageTitle,
'product_data' => $Products->getProductData($id),
'categorie' => $Category->getActiveCategory(),
'marque' => $Brands->getActiveBrands()
];
return $this->render_template('products/editbackup', $data);
}
}
public function remove()
{
$this->verifyRole('deleteProduct');
$product_id = $this->request->getPost('product_id');
$response = [];
$Products = new Products();
if ($product_id) {
if ($Products->remove($product_id)) {
$response['success'] = true;
$response['messages'] = "Successfully removed";
} else {
$response['success'] = false;
$response['messages'] = "Error in the database while removing the product information";
}
} else {
$response['success'] = false;
$response['messages'] = "Refersh the page again!!";
}
// Return JSON response
return $this->response->setJSON($response);
}
public function createByExcel()
{
$this->verifyRole("createProduct");
// 1) Récupération et validation du fichier
$file = $this->request->getFile('excel_product');
if (!$file || !$file->isValid() || $file->hasMoved()) {
return $this->response->setJSON([
'success' => false,
'messages' => "Aucun fichier valide reçu"
]);
}
$ext = strtolower($file->getClientExtension());
if (! in_array($ext, ['xls', 'xlsx'])) {
return $this->response->setJSON([
'success' => false,
'messages' => "Seuls les fichiers xls/xlsx sont autorisés"
]);
}
try {
// 2) Chargement du fichier Excel
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file->getTempName());
$sheet = $spreadsheet->getActiveSheet();
// 3) Lecture des données brutes et mapping des en-têtes
$allRows = $sheet->toArray(null, true, true, true);
if (count($allRows) < 2) {
return $this->response->setJSON([
'success' => false,
'messages' => "Le fichier ne contient aucune donnée"
]);
}
$headerRow = array_shift($allRows);
$map = [];
foreach ($headerRow as $col => $heading) {
$h = mb_strtolower(trim($heading));
$h = str_replace(['', '', '“', '”'], '\'', $h);
$h = iconv('UTF-8', 'ASCII//TRANSLIT', $h);
$h = preg_replace('/[^a-z0-9_]/', '_', $h);
$h = preg_replace('/_+/', '_', $h);
$h = trim($h, '_');
switch ($h) {
case 'designation':
case 'nom':
$map[$col] = 'name'; break;
case 'n_serie':
$map[$col] = 'sku'; break;
case 'prix_ar':
$map[$col] = 'prix_vente'; break;
case 'prix_d_achat':
case 'prix_dachat':
case 'prixd_achat':
$map[$col] = 'price'; break;
case 'marque':
$map[$col] = 'marque'; break;
case 'description':
$map[$col] = 'description'; break;
case 'code_moteur':
case 'n_moteur':
$map[$col] = 'numero_de_moteur'; break;
case 'chassis':
case 'chasis':
$map[$col] = 'chasis'; break;
case 'date_arrivage':
case 'date_d_arivage':
$map[$col] = 'date_arrivage'; break;
case 'puissance':
$map[$col] = 'puissance'; break;
case 'availability':
case 'disponibilite':
$map[$col] = 'availability'; break;
case 'piece':
case 'piece_manquant':
$map[$col] = 'is_piece'; break;
case 'cle':
$map[$col] = 'cler'; break;
case 'categories':
case 'categorie_id':
$map[$col] = 'categorie_id'; break;
case 'etat':
case 'etats':
$map[$col] = 'etats'; break;
case 'magasin':
$map[$col] = 'store_id'; break;
case 'info_manquekit':
case 'infomanquekit':
$map[$col] = 'infoManquekit'; break;
case 'info':
case 'info_piece':
$map[$col] = 'info'; break;
case 'info_manque':
$map[$col] = 'infoManque'; break;
case 'image':
case 'image_s':
$map[$col] = 'image'; break;
default:
// Non mappé
break;
}
}
// 4) Extraction des images intégrées, si présent
$imagesMap = [];
foreach ($sheet->getDrawingCollection() as $drawing) {
if ($drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing) {
$coord = $drawing->getCoordinates();
$extImg = pathinfo($drawing->getPath(), PATHINFO_EXTENSION);
$name = uniqid('img_') . ".$extImg";
$dir = FCPATH . 'assets/images/product_image/';
if (! is_dir($dir)) {
mkdir($dir, 0777, true);
}
file_put_contents($dir . $name, file_get_contents($drawing->getPath()));
$imagesMap[$coord] = $name;
}
}
// 5) Chargement des modèles
$ProductsModel = new \App\Models\Products();
$ProductsModel->skipValidation(true);
$BrandsModel = new \App\Models\Brands();
$CatModel = new \App\Models\Category();
$countInserted = 0;
// 6) Boucle sur chaque ligne de données
foreach ($allRows as $rowIndex => $row) {
$data = [];
// Lecture des cellules formatées pour chaque champ mappé
foreach ($map as $col => $field) {
$cellValue = $sheet
->getCell($col . ($rowIndex + 2))
->getFormattedValue();
$data[$field] = trim((string)$cellValue);
}
if (empty($data['name'])) {
continue; // champ désignation vide
}
// Conversion du prix AR : capture tous les groupes de chiffres
if (! empty($data['prix_vente'])) {
preg_match_all('/\d+/', $data['prix_vente'], $matches);
$digits = implode('', $matches[0]); // ex. ["2","000","000"] => "2000000"
$data['prix_vente'] = intval($digits);
} else {
$data['prix_vente'] = 0;
}
// Valeurs par défaut
$data['qty'] = 1;
$data['product_sold'] = 0;
$data['availability'] = isset($data['availability'])
? (strtolower($data['availability']) === 'oui' ? 1 : 0)
: 0;
$data['is_piece'] = isset($data['is_piece'])
? (strtolower($data['is_piece']) === 'oui' ? 1 : 0)
: 0;
$data['cler'] = isset($data['cler'])
? (strtolower($data['cler']) === 'oui' ? 1 : 0)
: 1;
$data['etats'] = isset($data['etats'])
? (strtolower($data['etats']) === 'kit' ? 1 : 0)
: 1;
// Association dimage si présente
foreach ($map as $col => $field) {
if ($field === 'image') {
$coordImg = $col . ($rowIndex + 2);
if (isset($imagesMap[$coordImg])) {
$data['image'] = $imagesMap[$coordImg];
}
break;
}
}
// Gestion des clés étrangères
if (! empty($data['marque'])) {
$data['marque'] = $BrandsModel->getOrCreateIdByName($data['marque']);
}
if (! empty($data['categorie_id'])) {
$labels = array_map('trim', explode(',', $data['categorie_id']));
$catIds = [];
foreach ($labels as $label) {
if ($label !== '') {
$catIds[] = $CatModel->getOrCreateIdByName($label);
}
}
$data['categorie_id'] = $catIds;
}
if (! empty($data['store_id'])) {
// store_id depuis la session
$Store = new Stores();
$store = $Store->getIdStoreByName($data['store_id']);
$data['store_id'] = $store;
}
// Insertion
$id = $ProductsModel->insert($data);
if ($id !== false) {
$countInserted++;
}
}
// 7) Notification et réponse
$Notification = new \App\Controllers\NotificationController();
$user = session()->get('user');
$Notification->createNotification(
"$countInserted produits ajoutés",
"COMMERCIALE",
(int)$user['store_id'],
"avances"
);
return $this->response->setJSON([
'success' => true,
'messages' => "Produits importés avec succès ($countInserted)"
]);
} catch (\Exception $e) {
log_message('error', $e->getMessage());
return $this->response->setJSON([
'success' => false,
'messages' => "Erreur pendant limport : " . $e->getMessage()
]);
}
}
}