diff --git a/app/Controllers/AvanceController.php b/app/Controllers/AvanceController.php index ed911e2b..fe00e709 100644 --- a/app/Controllers/AvanceController.php +++ b/app/Controllers/AvanceController.php @@ -1635,8 +1635,10 @@ private function generatePrintableInvoiceHTML($avance, $productName, $productDet Facture Avance - KELY SCOOTERS -
- -
-

KELY SCOOTERS

-
-
-
NIF: 401 840 5554
-
STAT: 46101 11 2024 00317
-
-
-
Contact: +261 34 27 946 35 / +261 34 07 079 69
-
Antsakaviro en face WWF
+ +
+
+ +
+

KELY SCOOTERS

+
+
+
NIF: 401 840 5554
+
STAT: 46101 11 2024 00317
+
+
+
Contact: +261 34 27 946 35 / +261 34 07 079 69
+
Antsakaviro en face WWF
+
-
- - -
-
-

FACTURE

-
Date: {$avanceDate}
-
N°: {$avanceNumber}CI 2025
-
-
DOIT ORIGINAL
-
- - -
-
NOM: {$customerName} ({$customerPhone})
-
CIN: {$customerCin}
-
PC: {$grossAmount} Ar
-
AVANCE: {$avanceAmount} Ar
-
RAP: {$amountDue} Ar
-
- - - - - - - - - - - - - - - - - - - -
MARQUEN°MOTEURPUISSANCERAP (Ariary)
{$marque}{$numeroMoteur}{$puissance}{$amountDue}
- - -
-

FIFANEKENA ARA-BAROTRA (Réservations)

-

Ry mpanjifa hajaina,

-

Natao ity fifanekena ity mba hialana amin'ny fivadihana hampitokisana amin'ny andaniny sy ankilany.

- -
- Andininy faha-1: FAMANDRAHANA SY FANDOAVAM-BOLA -

Ny mpividy dia manao famandrahana amin'ny alalan'ny fandoavambola mihoatra ny 25 isan-jato amin'ny vidin'entana rehetra (avances).

-
-
- Andininy faha-2: FANDOAVAM-BOLA REHEFA TONGA NY ENTANA (ARRIVAGE) -

Rehefa tonga ny moto/pieces dia tsy maintsy mandoa ny 50 isan-jato ny vidin'entana ny mpamandrika.

-

Manana 15 andro kosa adoavana ny 25 isan-jato raha misy tsy fahafahana alohan'ny famoahana ny entana.

+ +
+
+

FACTURE

+
Date: {$avanceDate}
+
N°: {$avanceNumber}CI 2025
+
+
DOIT ORIGINAL
-
- Andininy faha-3: FAMERENANA VOLA -

Raha toa ka misy antony tsy hakana ny entana indray dia tsy mamerina ny vola efa voaloha (avance) ny société.

+ +
+
NOM: {$customerName} ({$customerPhone})
+
CIN: {$customerCin}
+
PC: {$grossAmount} Ar
+
AVANCE: {$avanceAmount} Ar
+
RAP: {$amountDue} Ar
-
- Andininy faha-4: FEPETRA FANAMPINY -
    -
  • Tsy misafidy raha toa ka mamafa no ifanarahana.
  • -
  • Tsy azo atao ny mamerina ny entana efa nofandrahana.
  • -
  • Tsy azo atao ny manakalo ny entana efa nofandrahana.
  • -
-
+ + + + + + + + + + + + + + + + + + +
MARQUEN°MOTEURPUISSANCERAP (Ariary)
{$marque}{$numeroMoteur}{$puissance}{$amountDue}
+ +
- - -
-
-

NY MPAMANDRIKA

-
Signature
-
-
-

NY MPIVAROTRA

-
- KELY SCOOTERS
- NIF: 401 840 5554 +
+ + +
+
+ + +
+
+

CONDITIONS GÉNÉRALES

+
Date: {$avanceDate}
+
N°: {$avanceNumber}CI 2025
+ +
+ +
+

FIFANEKENA ARA-BAROTRA (Réservations)

+

Ry mpanjifa hajaina,

+

Natao ity fifanekena ity mba hialana amin'ny fivadihana hampitokisana amin'ny andaniny sy ankilany.

+ +
+ Andininy faha-1: FAMANDRAHANA SY FANDOAVAM-BOLA +

Ny mpividy dia manao famandrahana amin'ny alalan'ny fandoavambola mihoatra ny 25 isan-jato amin'ny vidin'entana rehetra (avances).

+
+ +
+ Andininy faha-2: FANDOAVAM-BOLA REHEFA TONGA NY ENTANA (ARRIVAGE) +

Rehefa tonga ny moto/pieces dia tsy maintsy mandoa ny 50 isan-jato ny vidin'entana ny mpamandrika.

+

Manana 15 andro kosa adoavana ny 25 isan-jato raha misy tsy fahafahana alohan'ny famoahana ny entana.

+
+ +
+ Andininy faha-3: FAMERENANA VOLA +

Raha toa ka misy antony tsy hakana ny entana indray dia tsy mamerina ny vola efa voaloha (avance) ny société.

+
+ +
+ Andininy faha-4: FEPETRA FANAMPINY +
    +
  • Tsy misafidy raha toa ka mamafa no ifanarahana.
  • +
  • Tsy azo atao ny mamerina ny entana efa nofandrahana.
  • +
  • Tsy azo atao ny manakalo ny entana efa nofandrahana.
  • +
+
+
+ + +
+ OBSERVATIONS / NOTES: +
+
+ + +
+
+

NY MPAMANDRIKA

+
Signature
+
+
+

NY MPIVAROTRA

+
+ KELY SCOOTERS
+ NIF: 401 840 5554 +
+
@@ -1877,7 +1919,6 @@ private function generatePrintableInvoiceHTML($avance, $productName, $productDet HTML; } - /** * ✅ NOUVELLE MÉTHODE : Traiter manuellement les avances expirées * URL: /avances/processExpiredAvances diff --git a/app/Controllers/OrderController.php b/app/Controllers/OrderController.php index 1faa286d..262f2479 100644 --- a/app/Controllers/OrderController.php +++ b/app/Controllers/OrderController.php @@ -341,6 +341,7 @@ class OrderController extends AdminController $posts = $this->request->getPost('product[]'); $rates = $this->request->getPost('rate_value[]'); $amounts = $this->request->getPost('amount_value[]'); + $puissances = $this->request->getPost('puissance[]'); // ✅ AJOUTER CETTE LIGNE $discount = (float)$this->request->getPost('discount') ?? 0; $gross_amount = $this->calculGross($amounts); @@ -400,13 +401,14 @@ class OrderController extends AdminController 'service_charge_rate' => 0, 'vat_charge_rate' => 0, 'vat_charge' => 0, - 'net_amount' => $net_amount, // ✅ Net amount = tranches OU montant_a_payer + 'net_amount' => $net_amount, 'discount' => $discount, - 'paid_status' => 2, // Toujours En Attente au départ + 'paid_status' => 2, 'user_id' => $user_id, 'amount_value' => $amounts, 'gross_amount' => $gross_amount, 'rate_value' => $rates, + 'puissance' => $puissances, // ✅ AJOUTER CETTE LIGNE 'store_id' => $users['store_id'], 'tranche_1' => $tranche_1, 'tranche_2' => $tranche_2, @@ -586,225 +588,252 @@ public function markAsDelivered() } - public function getProductValueById() - { - $product_id = $this->request->getPost('product_id'); - if ($product_id) { - $Products = new \App\Models\Products(); - $product_data = $Products->getProductData($product_id); - - $FourchettePrix = new \App\Models\FourchettePrix(); - $fourchette = $FourchettePrix->where('product_id', $product_id)->first(); - - $response = [ - 'id' => $product_data['id'], - 'sku' => $product_data['sku'], - 'name' => $product_data['name'], - 'prix_vente' => $product_data['prix_vente'], - 'prix_minimal' => $fourchette ? $fourchette['prix_minimal'] : 0, - ]; +public function getProductValueById() +{ + $product_id = $this->request->getPost('product_id'); + if ($product_id) { + $Products = new \App\Models\Products(); + $product_data = $Products->getProductData($product_id); + + $FourchettePrix = new \App\Models\FourchettePrix(); + $fourchette = $FourchettePrix->where('product_id', $product_id)->first(); + + // ✅ Extraire la puissance - Plusieurs méthodes + $puissance_extracted = ''; + + // Méthode 1: Chercher dans le champ puissance de la BD + if (!empty($product_data['puissance'])) { + $puissance_extracted = $product_data['puissance']; + } + + // Méthode 2: Chercher à la fin du nom (format: |150) + if (empty($puissance_extracted) && !empty($product_data['name'])) { + if (preg_match('/\|(\d+)(?:cc)?$/i', $product_data['name'], $matches)) { + $puissance_extracted = $matches[1]; + } + } + + // Méthode 3: Chercher n'importe où dans le nom (format: 150cc ou 150 CC) + if (empty($puissance_extracted) && !empty($product_data['name'])) { + if (preg_match('/(\d+)\s*cc/i', $product_data['name'], $matches)) { + $puissance_extracted = $matches[1]; + } + } + + // Log pour debug (à retirer en production) + log_message('info', 'Product ID: ' . $product_id . ' - Puissance: ' . $puissance_extracted); + + $response = [ + 'id' => $product_data['id'], + 'sku' => $product_data['sku'], + 'name' => $product_data['name'], + 'prix_vente' => $product_data['prix_vente'], + 'prix_minimal' => $fourchette ? $fourchette['prix_minimal'] : 0, + 'puissance' => $puissance_extracted, + 'numero_de_moteur' => $product_data['numero_de_moteur'] ?? '', + ]; + + return $this->response->setJSON($response); + } - return $this->response->setJSON($response); + return $this->response->setJSON(['error' => 'Product ID missing']); +} +public function getTableProductRow() +{ + $Products = new Products(); + $session = session(); + $users = $session->get('user'); + $store_id = $users['store_id']; + + $product_data = $Products->getProductData2($store_id); + + // ✅ Nettoyer les données pour ne pas afficher la puissance dans le select + foreach ($product_data as &$product) { + // Extraire la puissance si elle est dans le nom + if (!empty($product['name']) && preg_match('/\|(\d+)(?:cc)?$/i', $product['name'], $matches)) { + // Stocker la puissance séparément + if (empty($product['puissance'])) { + $product['puissance'] = $matches[1]; + } + } } + return $this->response->setJSON($product_data); +} - public function getTableProductRow() - { - $Products = new Products(); - $session = session(); - $users = $session->get('user'); - $store_id = $users['store_id']; + public function update(int $id) +{ + $this->verifyRole('updateOrder'); - $product_data = $Products->getProductData2($store_id); - die(var_dump($product_data)); - return $this->response->setJSON($product_data); - } + $data['page_title'] = $this->pageTitle; + $validation = \Config\Services::validation(); - public function update(int $id) - { - $this->verifyRole('updateOrder'); - - $data['page_title'] = $this->pageTitle; - $validation = \Config\Services::validation(); - - // ✅ NOUVELLE VÉRIFICATION : Bloquer UNIQUEMENT si statut = Validé (1) ou Validé et Livré (3) - $Orders = new Orders(); - $current_order = $Orders->getOrdersData($id); - - if (!$current_order) { - session()->setFlashData('errors', 'Commande introuvable.'); - return redirect()->to('orders/'); - } + $Orders = new Orders(); + $current_order = $Orders->getOrdersData($id); - // ✅ Bloquer UNIQUEMENT les statuts 1 (Validé) et 3 (Validé et Livré) - // Le statut 0 (Refusé) et 2 (En Attente) restent modifiables - if (in_array($current_order['paid_status'], [1, 3])) { + if (!$current_order) { + session()->setFlashData('errors', 'Commande introuvable.'); + return redirect()->to('orders/'); + } + + if (in_array($current_order['paid_status'], [1, 3])) { + session()->setFlashData('errors', 'Cette commande ne peut plus être modifiée car elle est déjà validée ou livrée.'); + return redirect()->to('orders/'); + } + + $validation->setRules([ + 'product' => 'required' + ]); + + $validationData = [ + 'product' => $this->request->getPost('product') + ]; + + $Company = new Company(); + $Products = new Products(); + $OrderItems = new OrderItems(); + + $session = session(); + $user = $session->get('user'); + $role = $user['group_name'] ?? null; + + if ($this->request->getMethod() === 'post' && $validation->run($validationData)) { + + $current_order_check = $Orders->getOrdersData($id); + if (in_array($current_order_check['paid_status'], [1, 3])) { session()->setFlashData('errors', 'Cette commande ne peut plus être modifiée car elle est déjà validée ou livrée.'); return redirect()->to('orders/'); } - - // Règles de validation - $validation->setRules([ - 'product' => 'required' - ]); - - $validationData = [ - 'product' => $this->request->getPost('product') + + $old_paid_status = $current_order['paid_status']; + + if ($role === 'COMMERCIALE') { + $paid_status = 2; + } else { + $paid_status = $this->request->getPost('paid_status'); + } + + $discount = $this->request->getPost('discount'); + $original_discount = $this->request->getPost('original_discount'); + if ($discount === '' || $discount === null) { + $discount = $original_discount; + } + + $dataUpdate = [ + 'customer_name' => $this->request->getPost('customer_name'), + 'customer_address' => $this->request->getPost('customer_address'), + 'customer_phone' => $this->request->getPost('customer_phone'), + 'customer_cin' => $this->request->getPost('customer_cin'), + 'gross_amount' => $this->request->getPost('gross_amount_value'), + 'service_charge_rate' => $this->request->getPost('service_charge_rate'), + 'service_charge' => max(0, (float)$this->request->getPost('service_charge_value')), + 'vat_charge_rate' => $this->request->getPost('vat_charge_rate'), + 'vat_charge' => max(0, (float)$this->request->getPost('vat_charge_value')), + 'net_amount' => $this->request->getPost('net_amount_value'), + 'discount' => (float)$discount, + 'paid_status' => $paid_status, + 'product' => $this->request->getPost('product'), + 'product_sold' => true, + 'rate_value' => $this->request->getPost('rate_value'), + 'amount_value' => $this->request->getPost('amount_value'), + 'puissance' => $this->request->getPost('puissance'), // ✅ AJOUT PUISSANCE + 'tranche_1' => $role !== 'COMMERCIALE' ? $this->request->getPost('tranche_1') : null, + 'tranche_2' => $role !== 'COMMERCIALE' ? $this->request->getPost('tranche_2') : null, + 'order_payment_mode' => $role !== 'COMMERCIALE' ? $this->request->getPost('order_payment_mode_1') : null, + 'order_payment_mode_1' => $role !== 'COMMERCIALE' ? $this->request->getPost('order_payment_mode_2') : null ]; - - $Company = new Company(); - $Products = new Products(); - $OrderItems = new OrderItems(); - - $session = session(); - $user = $session->get('user'); - $role = $user['group_name'] ?? null; - - if ($this->request->getMethod() === 'post' && $validation->run($validationData)) { - - // ✅ DOUBLE VÉRIFICATION avant l'update - $current_order_check = $Orders->getOrdersData($id); - if (in_array($current_order_check['paid_status'], [1, 3])) { - session()->setFlashData('errors', 'Cette commande ne peut plus être modifiée car elle est déjà validée ou livrée.'); - return redirect()->to('orders/'); - } - - $old_paid_status = $current_order['paid_status']; - - // ✅ Statut payé pour COMMERCIALE reste toujours "En attente" - if ($role === 'COMMERCIALE') { - $paid_status = 2; - } else { - $paid_status = $this->request->getPost('paid_status'); - } - - // Gestion remise - $discount = $this->request->getPost('discount'); - $original_discount = $this->request->getPost('original_discount'); - if ($discount === '' || $discount === null) { - $discount = $original_discount; + + if ($Orders->updates($id, $dataUpdate)) { + $order_item_data = $OrderItems->getOrdersItemData($id); + $product_ids = array_column($order_item_data, 'product_id'); + + $Notification = new NotificationController(); + + if ($old_paid_status == 2 && $paid_status == 1) { + $customer_name = $this->request->getPost('customer_name'); + $bill_no = $current_order['bill_no']; + + $Notification->createNotification( + "Commande validée: {$bill_no} - Client: {$customer_name}", + "SECURITE", + (int)$user['store_id'], + 'orders' + ); } - - $dataUpdate = [ - 'customer_name' => $this->request->getPost('customer_name'), - 'customer_address' => $this->request->getPost('customer_address'), - 'customer_phone' => $this->request->getPost('customer_phone'), - 'customer_cin' => $this->request->getPost('customer_cin'), - 'gross_amount' => $this->request->getPost('gross_amount_value'), - 'service_charge_rate' => $this->request->getPost('service_charge_rate'), - 'service_charge' => max(0, (float)$this->request->getPost('service_charge_value')), - 'vat_charge_rate' => $this->request->getPost('vat_charge_rate'), - 'vat_charge' => max(0, (float)$this->request->getPost('vat_charge_value')), - 'net_amount' => $this->request->getPost('net_amount_value'), - 'discount' => (float)$discount, - 'paid_status' => $paid_status, - 'product' => $this->request->getPost('product'), - 'product_sold' => true, - 'rate_value' => $this->request->getPost('rate_value'), - 'amount_value' => $this->request->getPost('amount_value'), - 'tranche_1' => $role !== 'COMMERCIALE' ? $this->request->getPost('tranche_1') : null, - 'tranche_2' => $role !== 'COMMERCIALE' ? $this->request->getPost('tranche_2') : null, - 'order_payment_mode' => $role !== 'COMMERCIALE' ? $this->request->getPost('order_payment_mode_1') : null, - 'order_payment_mode_1' => $role !== 'COMMERCIALE' ? $this->request->getPost('order_payment_mode_2') : null - ]; - - if ($Orders->updates($id, $dataUpdate)) { - $order_item_data = $OrderItems->getOrdersItemData($id); - $product_ids = array_column($order_item_data, 'product_id'); - - $Notification = new NotificationController(); - - // Notification pour la sécurité si commande validée - if ($old_paid_status == 2 && $paid_status == 1) { - $customer_name = $this->request->getPost('customer_name'); - $bill_no = $current_order['bill_no']; - - $Notification->createNotification( - "Commande validée: {$bill_no} - Client: {$customer_name}", - "SECURITE", - (int)$user['store_id'], - 'orders' - ); + + if ((float)$discount > 0) { + $productData = new Products(); + $product_data_results = []; + + foreach ($product_ids as $product_id) { + $product_data_results[] = $productData->getProductData((int) $product_id); } - - // Gestion demande de remise - if ((float)$discount > 0) { - $productData = new Products(); - $product_data_results = []; - - foreach ($product_ids as $product_id) { - $product_data_results[] = $productData->getProductData((int) $product_id); - } - - $product_lines = []; - foreach ($product_data_results as $product) { - if (isset($product['sku'], $product['price'])) { - $product_lines[] = "{$product['sku']}:{$product['price']}"; - } + + $product_lines = []; + foreach ($product_data_results as $product) { + if (isset($product['sku'], $product['price'])) { + $product_lines[] = "{$product['sku']}:{$product['price']}"; } - - $product_output = implode("\n", $product_lines); - - $data1 = [ - 'date_demande' => date('Y-m-d H:i:s'), - 'montant_demande' => $this->request->getPost('discount'), - 'total_price' => $this->request->getPost('amount_value'), - 'id_store' => $user['store_id'], - 'id_order' => $id, - 'product' => $product_output, - 'demande_status' => 'En attente' - ]; - - $Remise = new Remise(); - $Remise->updateRemise1($id, $data1); - - $Notification->createNotification( - "Une nouvelle demande de remise a été ajoutée", - "Direction", - (int)$user['store_id'] ?? null, - "remise/" - ); } - - session()->setFlashData('success', 'Commande mise à jour avec succès.'); - return redirect()->to('orders/'); - } else { - session()->setFlashData('errors', 'Une erreur est survenue lors de la mise à jour.'); - return redirect()->to('orders/update/' . $id); + + $product_output = implode("\n", $product_lines); + + $data1 = [ + 'date_demande' => date('Y-m-d H:i:s'), + 'montant_demande' => $this->request->getPost('discount'), + 'total_price' => $this->request->getPost('amount_value'), + 'id_store' => $user['store_id'], + 'id_order' => $id, + 'product' => $product_output, + 'demande_status' => 'En attente' + ]; + + $Remise = new Remise(); + $Remise->updateRemise1($id, $data1); + + $Notification->createNotification( + "Une nouvelle demande de remise a été ajoutée", + "Direction", + (int)$user['store_id'] ?? null, + "remise/" + ); } + + session()->setFlashData('success', 'Commande mise à jour avec succès.'); + return redirect()->to('orders/'); + } else { + session()->setFlashData('errors', 'Une erreur est survenue lors de la mise à jour.'); + return redirect()->to('orders/update/' . $id); } - - // Si GET ou validation échoue - $company = $Company->getCompanyData(1); - $data['company_data'] = $company; - $data['is_vat_enabled'] = ($company['vat_charge_value'] > 0); - $data['is_service_enabled'] = ($company['service_charge_value'] > 0); - - $orders_data = $Orders->getOrdersData($id); - - // ✅ Ajouter un flag pour désactiver le formulaire UNIQUEMENT pour les statuts 1 et 3 - $data['is_editable'] = !in_array($orders_data['paid_status'], [1, 3]); - - // Montant tranches - $orders_data['montant_tranches'] = (!empty($orders_data['discount']) && $orders_data['discount'] > 0) - ? $orders_data['discount'] - : $orders_data['gross_amount']; - - $result = ['order' => $orders_data]; - $orders_item = $OrderItems->getOrdersItemData($orders_data['id']); - - foreach ($orders_item as $item) { - $result['order_item'][] = $item; - } - - $data['order_data'] = $result; - $data['products'] = $Products->getActiveProductData(); - $data['validation'] = $validation; - - return $this->render_template('orders/edit', $data); } + $company = $Company->getCompanyData(1); + $data['company_data'] = $company; + $data['is_vat_enabled'] = ($company['vat_charge_value'] > 0); + $data['is_service_enabled'] = ($company['service_charge_value'] > 0); + + $orders_data = $Orders->getOrdersData($id); + + $data['is_editable'] = !in_array($orders_data['paid_status'], [1, 3]); + + $orders_data['montant_tranches'] = (!empty($orders_data['discount']) && $orders_data['discount'] > 0) + ? $orders_data['discount'] + : $orders_data['gross_amount']; + + $result = ['order' => $orders_data]; + $orders_item = $OrderItems->getOrdersItemData($orders_data['id']); + + foreach ($orders_item as $item) { + $result['order_item'][] = $item; + } + + $data['order_data'] = $result; + $data['products'] = $Products->getActiveProductData(); + $data['validation'] = $validation; + + return $this->render_template('orders/edit', $data); +} public function lookOrder(int $id) { @@ -1025,15 +1054,19 @@ public function markAsDelivered() '; - foreach ($orders_items as $item) { - $product_data = $Products->getProductData($item['product_id']); - $html .= ' - ' . esc($product_data['sku']) . ' - ' . esc($product_data['numero_de_moteur']) . ' - - ' . number_format((float) $item['amount'], 2, '.', ' ') . ' - '; - } + foreach ($orders_items as $item) { + $product_data = $Products->getProductData($item['product_id']); + + // ✅ PRIORITÉ À LA PUISSANCE DE LA COMMANDE + $puissance_affichee = !empty($item['puissance']) ? $item['puissance'] : ($product_data['puissance'] ?? ''); + + $html .= ' + ' . esc($product_data['sku']) . ' + ' . esc($product_data['numero_de_moteur']) . ' + ✅ + ' . number_format((float) $item['amount'], 2, '.', ' ') . ' + '; + } $html .= ' @@ -1104,184 +1137,186 @@ public function markAsDelivered() } public function print(int $id) -{ - $this->verifyRole('viewOrder'); - - if ($id) { - $Orders = new Orders(); - $Company = new Company(); - $Products = new Products(); - $OrderItems = new OrderItems(); - - $order_data = $Orders->getOrdersData($id); - $orders_items = $OrderItems->getOrdersItemData($id); - $company_info = $Company->getCompanyData(1); - - $paid_status = ($order_data['paid_status'] == 1) - ? "Payé" - : "Non payé"; - - foreach ($orders_items as $index => $item) { - $product_data = $Products->getProductData($item['product_id']); - - echo ' - - - - - - - - -
-
' . esc($company_info['company_name']) . '
- -
-
-

Facture ID : ' . esc($order_data['bill_no']) . '

-

NIF : ' . esc($company_info['NIF']) . '

-

STAT : ' . esc($company_info['STAT']) . '

-

- Contact : - ' . esc($company_info['phone']) . ' - ' . esc($company_info['phone2']) . ' -

-

Magasin : ' . esc($this->returnStore($order_data['store_id'])) . '

-
-
-

Nom: ' . esc($order_data['customer_name']) . '

-

Adresse: ' . esc($order_data['customer_address']) . '

-

Téléphone: ' . esc($order_data['customer_phone']) . '

-

CIN: ' . esc($order_data['customer_cin']) . '

-

-

Antananarivo le ' . esc(date('d/m/Y')) . '

-
-
- - - - - - - - - - - - - - - - - - -
MarqueMoteurPuissancePrix
' . esc($product_data['sku']) . '' . esc($product_data['numero_de_moteur']) . '' . number_format((float)$item['amount'], 2, '.', ' ') . '
- - - - - - - - - - - - - - - - - - - - - - '; - - if (!empty($order_data['order_payment_mode'])) { - echo ''; + .invoice-header { + background: #007bff !important; + color: white; + text-align: center; + font-size: 18px; + font-weight: bold; + padding: 10px; + border-radius: 10px 10px 0 0; } - - if (!empty($order_data['tranche_1'])) { - echo ''; + .invoice-footer { + background: #007bff !important; + color: white; + text-align: center; + font-size: 14px; + padding: 10px; + border-radius: 0 0 10px 10px; + margin-top: 12px; } - - if (!empty($order_data['tranche_2'])) { - echo ''; + table { width: 100%; border-collapse: collapse; } + th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; } + th { background: #e9ecef; } + input { + border: none; + outline: none; + width: 100%; + font-size: 14px; } - - echo '
Total:' . number_format($item['amount'] - ($item['amount'] * 0.2), 2, '.', ' ') . '
TVA:' . number_format($item['amount'] * 0.2, 2, '.', ' ') . '
Réduction:' . number_format($order_data['discount'], 2, '.', ' ') . '
Total à payer:' . number_format($item['amount'] - $order_data['discount'], 2, '.', ' ') . '
Statut:' . $paid_status . '
Mode de paiement:' . esc($order_data['order_payment_mode']) . '
Tranche 1:' . number_format((float)$order_data['tranche_1'], 2, '.', ' ') . '
Tranche 2:' . number_format((float)$order_data['tranche_2'], 2, '.', ' ') . '
- -
-

L\'acheteur

-

Le vendeur

-
- - - -'; + + '; + } } } -} - public function remove() { @@ -1347,71 +1382,70 @@ public function markAsDelivered() } -public function print3(int $id) -{ - // Vérification du rôle - $this->verifyRole('viewOrder'); - - if (!$id) { - return $this->response->setStatusCode(400, 'ID manquant'); - } - - // Instanciation des modèles - $Orders = new Orders(); - $Company = new Company(); - $OrderItems = new OrderItems(); - $Products = new Products(); - - // Récupération des données - $order_data = $Orders->getOrdersData($id); - $items = $OrderItems->getOrdersItemData($id); - $company_info = $Company->getCompanyData(1); - - // Statut de paiement - $paid_status = $order_data['paid_status'] == 1 - ? "Payé" - : "Non payé"; - - // STYLE COMMUN - $style = ' - - '; - - // --- FACTURES : Une par produit --- - foreach ($items as $item) { - $product_data = $Products->getProductData($item['product_id']); - $unitPrice = (float)$item['amount']; - $quantity = isset($item['qty']) ? (int)$item['qty'] : 1; - $subtotal = $unitPrice * $quantity; - $vatAmount = $subtotal * 0.2; - $discount = (float)$order_data['discount']; - $totalNet = $subtotal + $vatAmount - $discount; - - echo ' + + $Orders = new Orders(); + $Company = new Company(); + $OrderItems = new OrderItems(); + $Products = new Products(); + + $order_data = $Orders->getOrdersData($id); + $items = $OrderItems->getOrdersItemData($id); + $company_info = $Company->getCompanyData(1); + + $paid_status = $order_data['paid_status'] == 1 + ? "Validé" + : "Refusé"; + + // STYLE COMMUN + $style = ' + + '; + + // --- FACTURES : Une par produit --- + foreach ($items as $item) { + $product_data = $Products->getProductData($item['product_id']); + + // ✅ PRIORITÉ À LA PUISSANCE DE LA COMMANDE + $puissance_affichee = !empty($item['puissance']) + ? $item['puissance'] + : (!empty($product_data['puissance']) ? $product_data['puissance'] : ''); + + $unitPrice = (float)$item['amount']; + $quantity = isset($item['qty']) ? (int)$item['qty'] : 1; + $subtotal = $unitPrice * $quantity; + $vatAmount = $subtotal * 0.2; + $discount = (float)$order_data['discount']; + $totalNet = $subtotal + $vatAmount - $discount; + + echo ' @@ -1436,45 +1470,45 @@ public function print3(int $id)

CIN: ' . esc($order_data['customer_cin']) . '

- + - + - +
MarqueMoteurPuissancePrix unitaire
MarqueMoteurPuissance (CC)Prix unitaire
' . esc($product_data['sku']) . ' ' . esc($product_data['numero_de_moteur']) . '' . esc($product_data['puissance']) . ' ' . number_format($unitPrice, 2, '.', ' ') . '
- + - - - - - '; - - if (!empty($order_data['order_payment_mode'])) { - echo ''; - } - - if (!empty($order_data['tranche_1'])) { - echo ''; - } - - if (!empty($order_data['tranche_2'])) { - echo ''; - } - - echo '
Total:
TVA (20%):
Réduction:
Total à payer:
Statut:
Mode de paiement:
Tranche 1:
Tranche 2:
- + Total HT:' . number_format($subtotal, 2, '.', ' ') . ' Ar + TVA (20%):' . number_format($vatAmount, 2, '.', ' ') . ' Ar + Réduction:' . number_format($discount, 2, '.', ' ') . ' Ar + Total à payer:' . number_format($totalNet, 2, '.', ' ') . ' Ar + Statut:' . $paid_status . ''; + + if (!empty($order_data['order_payment_mode'])) { + echo 'Mode de paiement:' . esc($order_data['order_payment_mode']) . ''; + } + + if (!empty($order_data['tranche_1'])) { + echo 'Tranche 1:' . number_format((float)$order_data['tranche_1'], 2, '.', ' ') . ' Ar'; + } + + if (!empty($order_data['tranche_2'])) { + echo 'Tranche 2:' . number_format((float)$order_data['tranche_2'], 2, '.', ' ') . ' Ar'; + } + + echo ' +

L\'acheteur

Le vendeur

- + '; - } - - // --- BON DE COMMANDE : une seule fois après la boucle --- - echo ' - - - - - ' . $style . ' - - -
-
BON DE COMMANDE
-
-
-

Commande ID : ' . esc($order_data['order_no'] ?? $order_data['bill_no']) . '

-

Magasin : ' . esc($this->returnStore($order_data['store_id'])) . '

+ } + + // --- BON DE COMMANDE : une seule fois après la boucle --- + echo ' + + + + + ' . $style . ' + + +
+
BON DE COMMANDE
+
+
+

Commande ID : ' . esc($order_data['order_no'] ?? $order_data['bill_no']) . '

+

Magasin : ' . esc($this->returnStore($order_data['store_id'])) . '

+
+
+

Nom: ' . esc($order_data['customer_name']) . '

+

Adresse: ' . esc($order_data['customer_address']) . '

+

Téléphone: ' . esc($order_data['customer_phone']) . '

+

CIN: ' . esc($order_data['customer_cin']) . '

+
-
-

Nom: ' . esc($order_data['customer_name']) . '

-

Adresse: ' . esc($order_data['customer_address']) . '

-

Téléphone: ' . esc($order_data['customer_phone']) . '

-

CIN: ' . esc($order_data['customer_cin']) . '

+ + + + + + + + + + + '; + + $total_ht = 0; + foreach ($items as $item) { + $product_data = $Products->getProductData($item['product_id']); + + // ✅ PRIORITÉ À LA PUISSANCE DE LA COMMANDE + $puissance_affichee = !empty($item['puissance']) + ? $item['puissance'] + : (!empty($product_data['puissance']) ? $product_data['puissance'] : ''); + + $total_ht += (float)$item['amount']; + + echo ' + + + + + '; + } + + $tva = $total_ht * 0.2; + $total_ttc = $total_ht + $tva - $order_data['discount']; + + echo ' +
MarqueMoteurPuissance (CC)Prix
' . esc($product_data['sku']) . '' . esc($product_data['numero_de_moteur']) . '' . number_format((float)$item['amount'], 2, '.', ' ') . '
+ + + + + + +
Total HT:' . number_format($total_ht, 2, '.', ' ') . ' Ar
TVA (20%):' . number_format($tva, 2, '.', ' ') . ' Ar
Réduction:' . number_format($order_data['discount'], 2, '.', ' ') . ' Ar
Total à payer:' . number_format($total_ttc, 2, '.', ' ') . ' Ar
+ +
+

L\'acheteur

+

Le vendeur

+
+ +
- - - - - - - - - - - '; - - $total_ht = 0; - foreach ($items as $item) { - $product_data = $Products->getProductData($item['product_id']); - $total_ht += (float)$item['amount']; - echo ' - - - - - '; + + '; } - - $tva = $total_ht * 0.2; - $total_ttc = $total_ht + $tva - $order_data['discount']; - - echo ''; - echo '
MarqueMoteurPuissancePrix
' . esc($product_data['sku']) . '' . esc($product_data['numero_de_moteur']) . '' . number_format((float)$item['amount'], 2, '.', ' ') . '
- - - - - - -
Total:' . number_format($total_ht, 2, '.', ' ') . '
TVA:' . number_format($tva, 2, '.', ' ') . '
Réduction:' . number_format($order_data['discount'], 2, '.', ' ') . '
Total à payer:' . number_format($total_ttc, 2, '.', ' ') . '
'; - - echo '
-

L\'acheteur

-

Le vendeur

-
'; - - echo''; - echo '
'; - echo ''; - echo''; -} - // PRINT5 - Facture détaillée avec conditions générales // ==================================== public function print5(int $id) @@ -1657,16 +1697,13 @@ public function print5(int $id) '; - foreach ($items as $it) { - $details = $this->getOrderItemDetails($it); - - if (!$details) continue; - - $prixAffiche = ($discount > 0) ? $discount : $details['prix']; - - $html .= ' - - '.esc($details['product_name']); + foreach ($items as $it) { + $details = $this->getOrderItemDetails($it); + + if (!$details) continue; + + $prixAffiche = ($discount > 0) ? $discount : $details['prix']; + // Afficher le commentaire s'il existe if (!empty($details['commentaire'])) { @@ -1703,15 +1740,16 @@ public function print5(int $id) $prixAffiche = ($discount > 0) ? $discount : $details['prix']; + $html .= ' - - '.esc($details['marque']).' - '.esc($details['product_name']).' - '.esc($details['numero_moteur']).' - '.esc($details['numero_chassis']).' - '.esc($details['puissance']).' - '.number_format($prixAffiche, 0, '', ' ').' - '; + + '.esc($details['marque']).' + '.esc($details['product_name']).' + '.esc($details['numero_moteur']).' + '.esc($details['numero_chassis']).' + '.esc($details['puissance']).' + '.number_format($prixAffiche, 0, '', ' ').' + '; } } @@ -1776,7 +1814,7 @@ private function numberToWords(int $num): string if ($num === 0) { return 'zéro ariary'; } - + // Tableaux de base $units = [ '', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', @@ -1788,7 +1826,7 @@ private function numberToWords(int $num): string 5 => 'cinquante', 6 => 'soixante', 7 => 'soixante-dix', 8 => 'quatre-vingt', 9 => 'quatre-vingt-dix' ]; - + // Fonction récursive interne (sans la monnaie) $convert = function(int $n) use (&$convert, $units, $tens): string { if ($n < 20) { @@ -1824,16 +1862,15 @@ private function numberToWords(int $num): string // millions et plus $m = intdiv($n, 1000000); $rest = $n % 1000000; - $millionText = $m > 1 ? $convert($m) . ' million' : 'million'; + $millionText = $m > 1 ? $convert($m) . ' million' : 'un million'; // pas de 's' à million en francais return $millionText . ($rest ? ' ' . $convert($rest) : ''); }; - + // Construit le texte sans la monnaie, puis ajoute 'ariary' à la fin $words = $convert($num); return trim($words) . ' ariary'; } - /** * ✅ NOUVELLE MÉTHODE : Vérifier si une commande provient d'une avance "sur mer" */ @@ -1908,7 +1945,7 @@ private function getOrderItemDetails($item) 'marque' => $brandName, 'numero_moteur' => $product['numero_de_moteur'] ?? '', 'numero_chassis' => $product['chasis'] ?? $product['sku'] ?? '', - 'puissance' => $product['puissance'] ?? '', + 'puissance' => !empty($item['puissance']) ? $item['puissance'] : ($product['puissance'] ?? ''), // ✅ Priorité à la commande 'commentaire' => '', 'prix' => (float)$item['amount'] ]; diff --git a/app/Models/OrderItems.php b/app/Models/OrderItems.php index 09c49846..48ec685d 100644 --- a/app/Models/OrderItems.php +++ b/app/Models/OrderItems.php @@ -5,35 +5,23 @@ namespace App\Models; use CodeIgniter\Model; use DateTime; -/** - * table pivot - */ class OrderItems extends Model { - /** - * table name - * @var string - */ protected $table = 'orders_item'; - protected $allowedFields = ['order_id', 'product_id', 'qty', 'rate' , 'amount' ]; + protected $allowedFields = ['order_id', 'product_id', 'puissance', 'rate', 'amount']; public function insertOrderItem($data) { return $this->insert($data); } - /** - * get the orders item data - * @param mixed $order_id - * @return array|bool - */ public function getOrdersItemData($order_id = null) { if (!$order_id) { return false; } - return $this->where('order_id', $order_id)->findAll(); // Get items of a specific order + return $this->where('order_id', $order_id)->findAll(); } public function getAllSoldProductToday() { @@ -57,27 +45,22 @@ class OrderItems extends Model } public function updateOrderItem(int $id, array $data) -{ - return $this->where('order_id', $id) - ->set($data) - ->update(); -} - - -public function getProductIds(array $orderIds): array -{ - if (empty($orderIds)) { - return []; + { + return $this->where('order_id', $id) + ->set($data) + ->update(); } - $items = $this->select('product_id') - ->whereIn('order_id', $orderIds) - ->findAll(); - - // Extrait la colonne product_id - return array_column($items, 'product_id'); -} - + public function getProductIds(array $orderIds): array + { + if (empty($orderIds)) { + return []; + } + $items = $this->select('product_id') + ->whereIn('order_id', $orderIds) + ->findAll(); + return array_column($items, 'product_id'); + } } \ No newline at end of file diff --git a/app/Models/Orders.php b/app/Models/Orders.php index bff43c59..23689ba2 100644 --- a/app/Models/Orders.php +++ b/app/Models/Orders.php @@ -196,47 +196,43 @@ class Orders extends Model $orderItemModel = new OrderItems(); $productModel = new Products(); + // ✅ RÉCUPÉRER LE TABLEAU DES PUISSANCES + $puissances = $data['puissance'] ?? []; + // Loop through products and insert order items $count_product = count($post); for ($x = 0; $x < $count_product; $x++) { + // ✅ AJOUT DE LA PUISSANCE $items = [ 'order_id' => $order_id, 'product_id' => $post[$x], 'rate' => $data['rate_value'][$x], - 'qty' =>1, + 'qty' => 1, 'amount' => $data['amount_value'][$x], + 'puissance' => $puissances[$x] ?? 1, // ✅ CORRECTION ICI ]; $orderItemModel->insert($items); - - // Insert order item - - // // Decrease stock for the product + + // Decrease stock for the product $product_data = $productModel->find($post[$x]); if((int)$data['paid_status'] == 1){ - - if ($product_data) { - $product_sold = true; - - // Update product stock - $productModel->update($post[$x], ['product_sold' => $product_sold]); - } - else{ - $product_sold = false; - $productModel->update($post[$x], ['product_sold' => $product_sold]); + if ($product_data) { + $product_sold = true; + $productModel->update($post[$x], ['product_sold' => $product_sold]); + } else { + $product_sold = false; + $productModel->update($post[$x], ['product_sold' => $product_sold]); + } } } - } - return $order_id; // Return order ID if everything is successful + return $order_id; } catch (\Exception $e) { - // Log the exception for debugging (optional) log_message('error', 'Error creating order: ' . $e->getMessage()); - - return false; // Return false if an error occurs + return false; } } - /** * count order item * @param int $order_id @@ -284,6 +280,7 @@ class Orders extends Model 'order_id' => $id, 'product_id' => $data['product'][$x], 'rate' => $data['rate_value'][$x], + 'puissance' => $data['puissance'][$x], 'amount' => $data['amount_value'][$x], ]; diff --git a/app/Views/orders/createbyid.php b/app/Views/orders/createbyid.php index 3b76e42c..76d617d5 100644 --- a/app/Views/orders/createbyid.php +++ b/app/Views/orders/createbyid.php @@ -114,12 +114,16 @@


+ + - - + + + + @@ -129,31 +133,46 @@ id="product_1" name="product[]" style="width:100%;" onchange="getProductData(1)" required> + + + + - + +
ProduitPrix unitaireProduitPuissance (CC)Prix unitaire Montant
+ + - + autocomplete="off" value="" min="0"> + + +
- + + + +

@@ -186,6 +205,7 @@
+