You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1956 lines
80 KiB

<?php
namespace App\Controllers;
use DateTime;
use Mpdf\Mpdf;
use App\Models\Brands;
use App\Models\Caisse;
use App\Models\Orders;
use App\Models\Stores;
use App\Models\Company;
use App\Models\Category;
use App\Models\Products;
use App\Models\Attributes;
use App\Models\OrderItems;
use App\Models\Remise;
use PhpParser\Node\Stmt\Else_;
class OrderController extends AdminController
{
public function __construct()
{
parent::__construct();
}
private $pageTitle = 'Orders';
public function index()
{
$this->verifyRole('viewOrder');
$data['page_title'] = $this->pageTitle;
return $this->render_template('orders/index', $data);
}
public function fetchOrdersData()
{
// Load the required helpers
helper(['url', 'form']);
$Orders = new Orders();
$result = ['data' => []];
// Fetch orders data from the model
$data = $Orders->getOrdersData();
$session = session();
$users = $session->get('user');
if($users['group_name'] == "Caissière"){
foreach ($data as $key => $value) {
// $count_total_item = $Orders->countOrderItem($value['id']);
$date_time = date('d-m-Y h:i a', strtotime($value['date_time'])); // Combine date and time formatting
// Initialize buttons
$buttons = '';
if (in_array('viewOrder', $this->permission)) {
$buttons .= '<a target="_blank" href="' . site_url('orders/printDiv/' . $value['id']) . '" class="btn btn-default"><i class="fa fa-print"></i></a>';
}
if (in_array('viewOrder', $this->permission)) {
$buttons .= '
<a
href="#"
data-order-id="' . $value['id'] . '"
class="btn btn-default btn-view"
data-toggle="tooltip"
title="Voir">
<i class="fa fa-eye"></i>
</a>';
}
if (in_array('updateOrder', $this->permission) && $users["store_id"] == $value['store_id']) {
$buttons .= ' <a href="' . site_url('orders/update/' . $value['id']) . '" class="btn btn-primary"><i class="fa fa-pencil"></i></a>';
}
// Paid status label
$paid_status = ($value['paid_status'] == 1)
? '<span class="label label-success">Payé</span>'
: '<span class="label label-warning">Non payé</span>';
$date1 = new DateTime($date_time);
$date2 = new DateTime(); // Current date and time
// Calculate the difference in days
$interval = $date1->diff($date2);
$daysPassed = $interval->days;
$statuDate = '<span class="label label-success"></span>';
// die(var_dump($daysPassed));
$Notification = new NotificationController();
// die(var_dump($_SERVER['REQUEST_URI'] == "/orders/fetchOrdersData"));
$uri = $_SERVER['REQUEST_URI'];
if ($daysPassed < 8 && $value['paid_status'] == 2) {
$statuDate = '<span class="label label-success"> depuis ' . $daysPassed . ' Jours</span>';
} else if ($daysPassed >= 8 && $value['paid_status'] == 2) {
$Notification->createNotification("Conseil : Confirmation de reservation", "TOUS", (int)$value['store_id'], str_contains($uri, "fetchOrdersData") ? 'orders/#' : 'orders');
$statuDate = '<span class="label label-warning"> depuis ' . $daysPassed . ' Jours</span>';
} else if ($daysPassed >= 15 && $value['paid_status'] == 2) {
$Notification->createNotification("Conseil : Reservation expiré", "TOUS", (int)$value['store_id'], str_contains($uri, "fetchOrdersData") ? 'orders/#' : 'orders');
$statuDate = '<span class="label label-danger"> depuis ' . $daysPassed . ' Jours</span>';
}
$Orders_items= new OrderItems();
$sum_order_item = $Orders_items->getSumOrdersItemData($value['id']);
// Add data to the result array
$result['data'][$key] = [
$value['product_names'],
$value['user_name'],
$date_time . " <br >" . $statuDate,
$sum_order_item,
number_format((int) $value['net_amount'], 0, ',', ' '),
$paid_status,
$buttons
];
}
return $this->response->setJSON($result);
}
else if($users['group_name'] == "Direction" || $users['group_name'] == "Conseil"){
foreach ($data as $key => $value) {
// $count_total_item = $Orders->countOrderItem($value['id']);
$date_time = date('d-m-Y h:i a', strtotime($value['date_time'])); // Combine date and time formatting
// Initialize buttons
$buttons = '';
if (in_array('viewOrder', $this->permission)) {
$buttons .= '<a target="_blank" href="' . site_url('orders/printDiv/' . $value['id']) . '" class="btn btn-default"><i class="fa fa-print"></i></a>';
}
if (in_array('updateOrder', $this->permission)) {
$buttons .= ' <a href="' . site_url('orders/update/' . $value['id']) . '" class="btn btn-default"><i class="fa fa-pencil"></i></a>';
}
if (in_array('deleteOrder', $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>';
}
// Paid status label
$paid_status = ($value['paid_status'] == 1)
? '<span class="label label-success">Payé</span>'
: '<span class="label label-warning">Non payé</span>';
$date1 = new DateTime($date_time);
$date2 = new DateTime(); // Current date and time
// Calculate the difference in days
$interval = $date1->diff($date2);
$daysPassed = $interval->days;
$statuDate = '<span class="label label-success"></span>';
// die(var_dump($daysPassed));
$Notification = new NotificationController();
// die(var_dump($_SERVER['REQUEST_URI'] == "/orders/fetchOrdersData"));
$uri = $_SERVER['REQUEST_URI'];
if ($daysPassed < 8 && $value['paid_status'] == 2) {
$statuDate = '<span class="label label-success"> depuis ' . $daysPassed . ' Jours</span>';
} else if ($daysPassed >= 8 && $value['paid_status'] == 2) {
$Notification->createNotification("Conseil : Confirmation de reservation", "TOUS", (int)$value['store_id'], str_contains($uri, "fetchOrdersData") ? 'orders/#' : 'orders');
$statuDate = '<span class="label label-warning"> depuis ' . $daysPassed . ' Jours</span>';
} else if ($daysPassed >= 15 && $value['paid_status'] == 2) {
$Notification->createNotification("Conseil : Reservation expiré", "TOUS", (int)$value['store_id'], str_contains($uri, "fetchOrdersData") ? 'orders/#' : 'orders');
$statuDate = '<span class="label label-danger"> depuis ' . $daysPassed . ' Jours</span>';
}
$Orders_items= new OrderItems();
$sum_order_item = $Orders_items->getSumOrdersItemData($value['id']);
// Add data to the result array
$result['data'][$key] = [
$value['bill_no'],
$value['customer_name'],
$value['customer_phone'],
$date_time . " <br >" . $statuDate,
$sum_order_item,
number_format((int) $value['net_amount'], 0, ',', ' '),
$paid_status,
$buttons
];
}
return $this->response->setJSON($result);
}
else {
if($users['group_name'] !== "Direction" || $users['group_name'] !== "Conseil"){
foreach ($data as $key => $value) {
// $count_total_item = $Orders->countOrderItem($value['id']);
$date_time = date('d-m-Y h:i a', strtotime($value['date_time'])); // Combine date and time formatting
// Initialize buttons
$buttons = '';
if (in_array('viewOrder', $this->permission)) {
$buttons .= '<a target="_blank" href="' . site_url('orders/printDiv/' . $value['id']) . '" class="btn btn-default"><i class="fa fa-print"></i></a>';
}
if (in_array('updateOrder', $this->permission) && $users["id"] == $value['user_id']) {
$buttons .= ' <a href="' . site_url('orders/update/' . $value['id']) . '" class="btn btn-default"><i class="fa fa-pencil"></i></a>';
}
if (in_array('viewOrder', $this->permission)) {
$buttons .= '
<a
href="#"
data-order-id="' . $value['id'] . '"
class="btn btn-default btn-view"
data-toggle="tooltip"
title="Voir">
<i class="fa fa-eye"></i>
</a>';
}
if (in_array('deleteOrder', $this->permission) && $users["id"] == $value['user_id']) {
$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>';
}
// Paid status label
$paid_status = ($value['paid_status'] == 1)
? '<span class="label label-success">Payé</span>'
: '<span class="label label-warning">Non payé</span>';
$date1 = new DateTime($date_time);
$date2 = new DateTime(); // Current date and time
// Calculate the difference in days
$interval = $date1->diff($date2);
$daysPassed = $interval->days;
$statuDate = '<span class="label label-success"></span>';
// die(var_dump($daysPassed));
$Notification = new NotificationController();
// die(var_dump($_SERVER['REQUEST_URI'] == "/orders/fetchOrdersData"));
$uri = $_SERVER['REQUEST_URI'];
if ($daysPassed < 8 && $value['paid_status'] == 2) {
$statuDate = '<span class="label label-success"> depuis ' . $daysPassed . ' Jours</span>';
} else if ($daysPassed >= 8 && $value['paid_status'] == 2) {
$Notification->createNotification("Conseil : Confirmation de reservation", "TOUS", (int)$value['store_id'], str_contains($uri, "fetchOrdersData") ? 'orders/#' : 'orders');
$statuDate = '<span class="label label-warning"> depuis ' . $daysPassed . ' Jours</span>';
} else if ($daysPassed >= 15 && $value['paid_status'] == 2) {
$Notification->createNotification("Conseil : Reservation expiré", "TOUS", (int)$value['store_id'], str_contains($uri, "fetchOrdersData") ? 'orders/#' : 'orders');
$statuDate = '<span class="label label-danger"> depuis ' . $daysPassed . ' Jours</span>';
}
$Orders_items= new OrderItems();
$sum_order_item = $Orders_items->getSumOrdersItemData($value['id']);
// Add data to the result array
$result['data'][$key] = [
$value['product_names'],
$value['user_name'],
$date_time . " <br >" . $statuDate,
$sum_order_item,
number_format((int) $value['net_amount'], 0, ',', ' '),
$paid_status,
$buttons
];
}
return $this->response->setJSON($result);
}
}
// Return JSON response
}
/**
* function who check if the product is null
* and create notification about it
* @param array $product_id id of the product
* @param int $store_id id of the store
* @return void
*/
private function checkProductisNull(array $product_id, $store_id)
{
$notification = new NotificationController();
$product = new Products();
for ($i = 0; $i < count($product_id); $i++) {
$singleProduct = $product->getProductData($product_id[$i]);
if ($singleProduct['product_sold'] == true) {
$notification->createNotification("Produit en rupture de stock", "Conseil", $store_id, "products");
}
}
}
private function calculGross($request)
{
$amount = $request;
$montant = 0;
for ($i = 0; $i < \count($amount); $i++) {
$montant += $amount[$i];
}
return $montant;
}
public function create()
{
$this->verifyRole('createOrder');
$data['page_title'] = $this->pageTitle;
// Load validation service
$validation = \Config\Services::validation();
// echo '<pre>';
// die(var_dump($this->request->getPost('product[]')));
$products = $this->request->getPost('product[]');
// Then, manually check for uniqueness
if ($products !== null && (count($products) !== count(array_unique($products)))) {
return redirect()->back()->withInput()->with('errors', ['product' => 'Chaque produit sélectionné doit être unique.']);
}
// Set validation rules
$validation->setRules([
'product[]' => 'required'
]);
// echo '<pre>';
// die(var_dump($this->request->getPost()));
$validationData = [
'product[]' => $this->request->getPost('product[]')
];
$Orders = new Orders();
$Company = new Company();
$Products = new Products();
if ($this->request->getMethod() === 'post' && $validation->run($validationData)) {
$session = session();
$users = $session->get('user');
$user_id = $users['id'];
$bill_no = 'BILPR-' . strtoupper(substr(md5(uniqid(mt_rand(), true)), 0, 4));
// If validation passes
$data = [
'bill_no' => $bill_no,
'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'),
'date_time' => date('Y-m-d H:i:s'),
'service_charge_rate' => $this->request->getPost('service_charge_rate'),
'vat_charge_rate' => $this->request->getPost('vat_charge_rate'),
'vat_charge' => ($this->request->getPost('vat_charge_value') > 0) ? $this->request->getPost('vat_charge_value') : 0,
'net_amount' => $this->request->getPost('net_amount'),
'discount' => $this->request->getPost('discount'),
'paid_status' => 2,
'user_id' => $user_id,
// 'qty' => $this->request->getPost('qty[]'),
'amount_value' => $this->request->getPost('amount_value[]'),
'gross_amount' => $this->calculGross($this->request->getPost('amount_value[]')),
'rate_value' => $this->request->getPost('rate_value[]'),
'store_id' => $users['store_id'],
];
$posts = $this->request->getPost('product[]');
// echo '<pre>';
// die(var_dump($data));
$order_id = $Orders->create($data, $posts);
$Order_item1 = new OrderItems();
$order_item_data = $Order_item1->getOrdersItemData($order_id);
$product_ids = array_column($order_item_data, 'product_id');
$Notification = new NotificationController();
if ((int) (int) $this->request->getPost('discount') > 0) {
$productData = new Products();
$product_data_results = [];
foreach ($product_ids as $prod_id) {
$id = (int) $prod_id;
// Appel de la méthode pour chaque ID
$product_data_results[] = $productData->getProductData($id);
}
$product_lines = [];
foreach ($product_data_results as $product) {
if (isset($product['sku'], $product['price'])) {
$sku = $product['sku'];
$price = $product['price'];
$product_lines[] = "{$sku}:{$price}";
}
}
$product_output = implode("\n", $product_lines);
// data for the remise
$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' => $users['store_id'],
'id_order' => $order_id,
'product' => $product_output,
'demande_status' => 'En attente'
];
$Remise = new Remise();
$id_remise = $Remise->addDemande($data1);
$Notification->createNotification("Un nouveau demande de remise été ajouté", "Conseil", (int)$users['store_id'], 'remise');
}
if ($order_id) {
session()->setFlashdata('success', 'Créé avec succès');
$Notification->createNotification("Un nouveau commade ajouter", "Caissière", (int)$users['store_id'], "orders");
if ($users["group_name"] != "COMMERCIALE") {
$this->checkProductisNull($posts, $users['store_id']);
return redirect()->to('orders/update/' . $order_id);
} else {
return redirect()->to('orders/');
}
} else {
session()->setFlashdata('errors', 'Error occurred!!');
return redirect()->to('orders/create/');
}
} else {
// If validation fails
$company = $Company->getCompanyData(1);
$session = session();
$users = $session->get('user');
$store_id = $users['store_id'];
// Prepare data for the view
$data = [
'company_data' => $company,
'is_vat_enabled' => ($company['vat_charge_value'] > 0),
'is_service_enabled' => ($company['service_charge_value'] > 0),
'products' => $Products->getProductData2($store_id),
'validation' => $validation,
'page_title' => $this->pageTitle,
];
// Render the view with the prepared data
return $this->render_template('orders/create', $data);
}
}
public function getProductValueById()
{
$product_id = $this->request->getPost('product_id');
if ($product_id) {
$Products = new Products();
$product_data = $Products->getProductData($product_id);
return $this->response->setJSON($product_data);
}
}
public function getTableProductRow()
{
$Products = new Products();
$session = session();
$users = $session->get('user');
$store_id = $users['store_id'];
$product_data = $Products->getProductData2($store_id);
die(var_dump($product_data));
return $this->response->setJSON($product_data);
}
public function update(int $id)
{
$this->verifyRole('updateOrder');
$data['page_title'] = $this->pageTitle;
$validation = \Config\Services::validation();
// Définir les règles de validation
$validation->setRules([
'product' => 'required'
]);
$validationData = [
'product' => $this->request->getPost('product')
];
$Orders = new Orders();
$Company = new Company();
$Products = new Products();
$OrderItems = new OrderItems();
if ($this->request->getMethod() === 'post' && $validation->run($validationData)) {
$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' => $this->request->getPost('discount'),
'paid_status' => $this->request->getPost('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' => $this->request->getPost('tranche_1'),
'tranche_2' => $this->request->getPost('tranche_2'),
'order_payment_mode' => $this->request->getPost('order_payment_mode_1'),
'order_payment_mode_1' => $this->request->getPost('order_payment_mode_2')
];
if ($Orders->updates($id, $dataUpdate)) {
$order_item_data = $OrderItems->getOrdersItemData($id);
$product_ids = array_column($order_item_data, 'product_id');
$Notification = new NotificationController();
$discount = (int) $this->request->getPost('discount');
if ($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_output = implode("\n", $product_lines);
$session = session();
$users = $session->get('user');
$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' => $users['store_id'],
'id_order' => $id,
'product' => $product_output,
'demande_status' => 'En attente'
];
$Remise = new Remise();
$Remise->updateRemise1($id,$data1);
$Notification->createNotification("Un nouveau demande de remise a été ajouté", "Conseil", (int)$users['store_id'] ?? null, 'remise');
}
session()->setFlashData('success', 'Commande mise à jour avec succès.');
return redirect()->to('orders/update/' . $id);
} else {
session()->setFlashData('errors', 'Une erreur est survenue lors de la mise à jour.');
return redirect()->to('orders/update/' . $id);
}
}
// En cas d’échec de la validation ou si GET
$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);
$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)
{
$this->verifyRole('viewOrder');
$data['page_title'] = $this->pageTitle;
$Orders = new Orders();
$Company = new Company();
$Products = new Products();
$OrderItems = new OrderItems();
// En cas d’échec de la validation ou si GET
$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);
$sum_order_item = $OrderItems->getSumOrdersItemData($orders_data['id']);
$result = [
'order' => $orders_data,
'sum_order_data' => $sum_order_item
];
$orders_item = $OrderItems->getOrdersItemData($orders_data['id']);
foreach ($orders_item as $item) {
$result['order_item'][] = $item;
}
$data['order_data'] = $result;
$data['products'] = $Products->getActiveProductData();
return $this->response->setJSON($data);
}
/**
* return storename
* @param int $id
* @return string
*/
private function returnStore($id)
{
$Stores = new Stores();
$store = $Stores->getActiveStore();
$name = "";
foreach ($store as $key => $value) {
if ($value['id'] == $id) {
$name = $value['name'];
}
}
return $name;
}
public function print2(int $id)
{
$this->verifyRole('viewOrder');
if ($id) {
$Orders = new Orders();
$Company = new Company();
$Products = new Products();
$OrderItems = new OrderItems();
// Récupération des données
$order_data = $Orders->getOrdersData($id);
$orders_items = $OrderItems->getOrdersItemData($id);
$company_info = $Company->getCompanyData(1);
// die(\var_dump($orders_items));
$html = '';
// Vérifier si l'utilisateur a payé
$paid_status = ($order_data['paid_status'] == 1) ? "<span style='color: green; font-weight: bold;'>Payé</span>" : "<span style='color: red; font-weight: bold;'>Non payé</span>";
// Génération du HTML
$html .= '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="' . base_url('assets/bower_components/bootstrap/dist/css/bootstrap.min.css') . '">
<style>
body { font-size: 14px; font-family: Arial, sans-serif; }
.invoice-container {
max-width: 750px; /* Réduire la largeur du cadre */
margin: 20px auto;
padding: 20px;
border: 2px solid #007bff; /* Bordure plus visible */
border-radius: 10px;
background: #f0f8ff; /* Couleur de fond plus douce */
}
.invoice-header {
background: #007bff;
color: white;
text-align: center;
font-size: 18px;
font-weight: bold;
padding: 10px;
border-radius: 10px 10px 0 0;
}
.invoice-footer {
background: #007bff;
color: white;
text-align: center;
font-size: 14px;
padding: 10px;
border-radius: 0 0 10px 10px;
margin-top: 12px;
}
table { width: 100%; border-collapse: collapse; }
th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
th { background: #e9ecef; }
p, strong { color: #333; }
@media print {
body { font-size: 14px; font-family: Arial, sans-serif, margin: 1cm; }
@page { margin: 0; }
.invoice-container {
max-width: 750px;
margin: 20px auto;
padding: 20px;
border: 2px solid #007bff;
border-radius: 10px;
background: #f0f8ff;
}
.invoice-header {
background: #007bff !important;
color: white !important;
text-align: center;
font-size: 18px;
font-weight: bold;
padding: 10px;
border-radius: 10px 10px 0 0;
}
input {
border: none;
outline: none;
width: 100%;
font-size: 14px;
}
.invoice-footer {
background: #007bff !important;
color: white !important;
text-align: center;
font-size: 14px;
padding: 10px;
border-radius: 0 0 10px 10px;
margin-top: 12px;
}
table { width: 100%; border-collapse: collapse; }
th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
th { background: #e9ecef; }
p, strong { color: #333; } a
/* Supprimer l\'ombre et les bordures non nécessaires */
.invoice-container { box-shadow: none !important; border: none !important; }
/* Éviter que les couleurs soient supprimées à l\'impression */
* { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}
</style>
</head>
<body onload="window.print();">
<div class="invoice-container">
<div class="invoice-header" style="background: #007bff;color: white;text-align: center;font-size: 18px;font-weight: bold;padding: 10px;border-radius: 10px 10px 0 0; ">
' . esc($company_info['company_name']) . '
</div>
<div style="display: flex;justify-content: space-around;margin-top: 3%;">
<div>
<p><strong>Facture ID :</strong> ' . esc($order_data['bill_no']) . '</p>
<p><strong>NIF :</strong> ' . esc($company_info['NIF']) . '</p>
<p><strong>STAT :</strong> ' . esc($company_info['STAT']) . '</p>
<p style="display: flex; gap: 10px;">
<strong>Contact :</strong>
<span>' . esc($company_info['phone']) . '</span>
<span>' . esc($company_info['phone2']) . '</span>
</p>
<p><strong>Magasin :</strong> ' . esc($this->returnStore($order_data['store_id'])) . '</p>
</div>
<div>
<p><strong>Nom:</strong> ' . esc($order_data['customer_name']) . '</p>
<p><strong>Adresse:</strong> ' . esc($order_data['customer_address']) . '</p>
<p><strong>Téléphone:</strong> ' . esc($order_data['customer_phone']) . '</p>
<p><strong>CIN:</strong> ' . esc($order_data['customer_cin']) . '</p>
<br >
<br >
<p><strong>Antananarivo le</strong> ' . esc(date('d/m/Y')) . '</p>
</div>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>Marque</th>
<th>Moteur</th>
<th>Puissance</th>
<th>Prix</th>
</tr>
</thead>
<tbody>';
foreach ($orders_items as $item) {
$product_data = $Products->getProductData($item['product_id']);
$html .= '<tr>
<td>' . esc($product_data['sku']) . '</td>
<td>' . esc($product_data['numero_de_moteur']) . '</td>
<td><input type="text" name="customField" placeholder="Remplir ici" style="border: none; outline: none; width: 100%;" value="' . esc($product_data['puissance']) . '"></td>
<td style="text-align:right;">' . number_format((float) $item['amount'], 2, '.', ' ') . '</td>
</tr>';
}
$html .= ' </tbody>
</table>
<table class="table">
<tr>
<th>Total:</th>
<td>' . number_format(((float) $order_data['gross_amount'] - ((float) $order_data['gross_amount'] * 0.2)), 2, '.', ' ') . '</td>
</tr>
<tr>
<th>TVA:</th>
<td>' . number_format((((float) $order_data['gross_amount'] * 0.2)), 2, '.', ' ') . '</td>
</tr>';
$html .= '<tr>
<th>Réduction:</th>
<td>' . number_format((float) $order_data['discount'], 2, '.', ' ') . '</td>
</tr>
<tr>
<th>Total à payer:</th>
<td><strong>' . number_format((float) ($order_data['net_amount']), 2, '.', ' ') . '</strong></td>
</tr>
<tr>
<th>Statut:</th>
<td>' . $paid_status . '</td>
</tr>';
// Vérification et ajout des informations de paiement
if (!empty($order_data['order_payment_mode'])) {
$html .= '<tr>
<th>Mode de paiement:</th>
<td><strong>' . esc($order_data['order_payment_mode']) . '</strong></td>
</tr>';
}
if (!empty($order_data['tranche_1'])) {
$html .= '<tr>
<th>Tranche 1:</th>
<td><strong>' . number_format((float) $order_data['tranche_1'], 2, '.', ' ') . '</strong></td>
</tr>';
}
if (!empty($order_data['tranche_2'])) {
$html .= '<tr>
<th>Tranche 2:</th>
<td><strong>' . number_format((float) $order_data['tranche_2'], 2, '.', ' ') . '</strong></td>
</tr>';
}
$html .= '</table>
<div style="display: flex;align-items: center;justify-content: space-around;margin-bottom: 5%;">
<div>
<p style="font-weight:bold;">L\'acheteur</p>
</div>
<div>
<p style="font-weight:bold;">Le vendeur</p>
</div>
</div>
<div class="invoice-footer">
Merci pour votre achat !<br>
<strong style="color:white;">Original</strong>
</div>
</div>
</body>
</html>';
return $this->response->setBody($html);
}
}
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)
? "<span style='color: green; font-weight: bold;'>Payé</span>"
: "<span style='color: red; font-weight: bold;'>Non payé</span>";
foreach ($orders_items as $index => $item) {
$product_data = $Products->getProductData($item['product_id']);
echo '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="' . base_url('assets/bower_components/bootstrap/dist/css/bootstrap.min.css') . '">
<style>
body { font-size: 14px; font-family: Arial, sans-serif; margin: 0; padding: 0; }
.invoice-container {
max-width: 750px;
margin: 20px auto;
padding: 20px;
border: 2px solid #007bff;
border-radius: 10px;
background: #f0f8ff;
page-break-after: always;
}
.invoice-header {
background: #007bff !important;
color: white;
text-align: center;
font-size: 18px;
font-weight: bold;
padding: 10px;
border-radius: 10px 10px 0 0;
}
.invoice-footer {
background: #007bff !important;
color: white;
text-align: center;
font-size: 14px;
padding: 10px;
border-radius: 0 0 10px 10px;
margin-top: 12px;
}
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;
}
@media print {
body { font-size: 14px; font-family: Arial, sans-serif, margin: 1cm; }
@page { margin: 0; }
* { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body, .invoice-container {
margin: 0;
padding: 0;
border: none;
box-shadow: none;
}
.invoice-container {
page-break-after: always;
}
}
</style>
</head>
<body onload="window.print()">
<div class="invoice-container">
<div class="invoice-header">' . esc($company_info['company_name']) . '</div>
<div style="display: flex; justify-content: space-around; margin-top: 3%;">
<div>
<p><strong>Facture ID :</strong> ' . esc($order_data['bill_no']) . '</p>
<p><strong>NIF :</strong> ' . esc($company_info['NIF']) . '</p>
<p><strong>STAT :</strong> ' . esc($company_info['STAT']) . '</p>
<p style="display: flex; gap: 10px;">
<strong>Contact :</strong>
<span>' . esc($company_info['phone']) . '</span>
<span>' . esc($company_info['phone2']) . '</span>
</p>
<p><strong>Magasin :</strong> ' . esc($this->returnStore($order_data['store_id'])) . '</p>
</div>
<div>
<p><strong>Nom:</strong> ' . esc($order_data['customer_name']) . '</p>
<p><strong>Adresse:</strong> ' . esc($order_data['customer_address']) . '</p>
<p><strong>Téléphone:</strong> ' . esc($order_data['customer_phone']) . '</p>
<p><strong>CIN:</strong> ' . esc($order_data['customer_cin']) . '</p>
<br><br>
<p><strong>Antananarivo le</strong> ' . esc(date('d/m/Y')) . '</p>
</div>
</div>
<table class="table">
<thead>
<tr>
<th>Marque</th>
<th>Moteur</th>
<th>Puissance</th>
<th>Prix</th>
</tr>
</thead>
<tbody>
<tr>
<td>' . esc($product_data['sku']) . '</td>
<td>' . esc($product_data['numero_de_moteur']) . '</td>
<td><input type="text" value="' . esc($product_data['puissance']) . '" placeholder="Remplir ici"></td>
<td style="text-align:right;">' . number_format((float)$item['amount'], 2, '.', ' ') . '</td>
</tr>
</tbody>
</table>
<table class="table">
<tr>
<th>Total:</th>
<td>' . number_format($item['amount'] - ($item['amount'] * 0.2), 2, '.', ' ') . '</td>
</tr>
<tr>
<th>TVA:</th>
<td>' . number_format($item['amount'] * 0.2, 2, '.', ' ') . '</td>
</tr>
<tr>
<th>Réduction:</th>
<td>' . number_format($order_data['discount'], 2, '.', ' ') . '</td>
</tr>
<tr>
<th>Total à payer:</th>
<td><strong>' . number_format($item['amount'] - $order_data['discount'], 2, '.', ' ') . '</strong></td>
</tr>
<tr>
<th>Statut:</th>
<td>' . $paid_status . '</td>
</tr>';
if (!empty($order_data['order_payment_mode'])) {
echo '<tr><th>Mode de paiement:</th><td><strong>' . esc($order_data['order_payment_mode']) . '</strong></td></tr>';
}
if (!empty($order_data['tranche_1'])) {
echo '<tr><th>Tranche 1:</th><td><strong>' . number_format((float)$order_data['tranche_1'], 2, '.', ' ') . '</strong></td></tr>';
}
if (!empty($order_data['tranche_2'])) {
echo '<tr><th>Tranche 2:</th><td><strong>' . number_format((float)$order_data['tranche_2'], 2, '.', ' ') . '</strong></td></tr>';
}
echo '</table>
<div style="display: flex; justify-content: space-around; margin-top: 5%;">
<div><p style="font-weight:bold;">L\'acheteur</p></div>
<div><p style="font-weight:bold;">Le vendeur</p></div>
</div>
<div class="invoice-footer">
Merci pour votre achat !<br>
<strong style="color:white;">Original</strong>
</div>
</div>
</body>
</html>';
}
}
}
public function remove()
{
$this->verifyRole('deleteOrder');
$order_id = $this->request->getPost('order_id');
$response = [];
if ($order_id) {
$Orders = new Orders();
if ($Orders->remove($order_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 $this->response->setJSON($response);
}
public function createById(int $id)
{
$this->verifyRole('createOrder');
$data['page_title'] = $this->pageTitle;
$Company = new Company();
$Products = new Products();
// If validation fails
$company = $Company->getCompanyData(1);
// Prepare data for the view
$data = [
'company_data' => $company,
'is_vat_enabled' => ($company['vat_charge_value'] > 0),
'is_service_enabled' => ($company['service_charge_value'] > 0),
'products' => $Products->getProductData($id),
'totalqtt' => $Products->getProductData($id)['qty'],
'pu' => $Products->getProductData($id)['prix_vente'],
'page_title' => $this->pageTitle,
];
return $this->render_template('orders/createbyid', $data);
}
// update caisse
public function update_caisse($data)
{
$p1 = 0;
$p2 = 0;
$op = "";
$p3 = 0;
$dest = "";
if ($data['tranche2']) {
if ($data['order']) {
# code...
}
}
}
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
? "<span style='color: green; font-weight: bold;'>Payé</span>"
: "<span style='color: red; font-weight: bold;'>Non payé</span>";
// STYLE COMMUN
$style = '
<style>
body { font-family: Arial, sans-serif; font-size:14px; margin:0; padding:0; }
.invoice-container { max-width:750px; margin:20px auto; padding:20px;
border:2px solid #007bff; border-radius:10px; page-break-after:always; }
.invoice-header { background:#007bff !important; color:#fff; text-align:center;
font-size:18px; padding:10px; border-radius:10px 10px 0 0; }
.invoice-footer { background:#007bff !important; color:#fff; text-align:center;
font-size:14px; padding:10px; border-radius:0 0 10px 10px; margin-top:12px; }
.info { display:flex; justify-content:space-between; margin-top:15px; }
table { width:100%; border-collapse:collapse; margin-top:15px; }
th, td { border:1px solid #ddd; padding:8px; text-align:left; }
th { background:#e9ecef; }
.summary {
width: 80%;
margin: 20px 0;
margin-right: 0;
}
.summary th, .summary td { border:none; padding:4px; text-align:right; }
.summary th { text-align:left; }
@media print {
body { font-size: 14px; font-family: Arial, sans-serif, margin: 1cm; }
@page { margin: 0; }
* { -webkit-print-color-adjust:exact; print-color-adjust:exact; } }
</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 '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="' . base_url('assets/bower_components/bootstrap/dist/css/bootstrap.min.css') . '">
' . $style . '
</head>
<body onload="window.print()">
<div class="invoice-container">
<div class="invoice-header">FACTURE</div>
<div class="info">
<div>
<p><strong>Facture ID :</strong> ' . esc($order_data['bill_no']) . '</p>
<p><strong>NIF :</strong> ' . esc($company_info['NIF']) . '</p>
<p><strong>STAT :</strong> ' . esc($company_info['STAT']) . '</p>
<p><strong>Contact :</strong> ' . esc($company_info['phone']) . ' / ' . esc($company_info['phone2']) . '</p>
<p><strong>Magasin :</strong> ' . esc($this->returnStore($order_data['store_id'])) . '</p>
</div>
<div>
<p><strong>Nom:</strong> ' . esc($order_data['customer_name']) . '</p>
<p><strong>Adresse:</strong> ' . esc($order_data['customer_address']) . '</p>
<p><strong>Téléphone:</strong> ' . esc($order_data['customer_phone']) . '</p>
<p><strong>CIN:</strong> ' . esc($order_data['customer_cin']) . '</p>
</div>
</div>
<table>
<thead><tr><th>Marque</th><th>Moteur</th><th>Puissance</th><th>Prix unitaire</th></tr></thead>
<tbody>
<tr>
<td>' . esc($product_data['sku']) . '</td>
<td>' . esc($product_data['numero_de_moteur']) . '</td>
<td>' . esc($product_data['puissance']) . '</td>
<td>' . number_format($unitPrice, 2, '.', ' ') . '</td>
</tr>
</tbody>
</table>
<table class="table summary">
<tr><th>Total:</th><td></td></tr>
<tr><th>TVA (20%):</th><td></td></tr>
<tr><th>Réduction:</th><td></td></tr>
<tr><th>Total à payer:</th><td><strong></strong></td></tr>
<tr><th>Statut:</th><td></td></tr>';
if (!empty($order_data['order_payment_mode'])) {
echo '<tr><th>Mode de paiement:</th><td></td></tr>';
}
if (!empty($order_data['tranche_1'])) {
echo '<tr><th>Tranche 1:</th><td></td></tr>';
}
if (!empty($order_data['tranche_2'])) {
echo '<tr><th>Tranche 2:</th><td></td></tr>';
}
echo '</table>
<div style="display: flex; justify-content: space-around; margin-top: 5%;">
<div><p style="font-weight:bold;">L\'acheteur</p></div>
<div><p style="font-weight:bold;">Le vendeur</p></div>
</div>
<div class="invoice-footer">
Merci pour votre achat !<br>
<strong style="color:white;">Original</strong>
</div>
</div>
</body>
</html>';
}
// --- BON DE COMMANDE : une seule fois après la boucle ---
echo '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="' . base_url('assets/bower_components/bootstrap/dist/css/bootstrap.min.css') . '">
' . $style . '
</head>
<body onload="window.print()">
<div class="invoice-container">
<div class="invoice-header">BON DE COMMANDE</div>
<div class="info">
<div>
<p><strong>Commande ID :</strong> ' . esc($order_data['order_no'] ?? $order_data['bill_no']) . '</p>
<p><strong>Magasin :</strong> ' . esc($this->returnStore($order_data['store_id'])) . '</p>
</div>
<div>
<p><strong>Nom:</strong> ' . esc($order_data['customer_name']) . '</p>
<p><strong>Adresse:</strong> ' . esc($order_data['customer_address']) . '</p>
<p><strong>Téléphone:</strong> ' . esc($order_data['customer_phone']) . '</p>
<p><strong>CIN:</strong> ' . esc($order_data['customer_cin']) . '</p>
</div>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>Marque</th>
<th>Moteur</th>
<th>Puissance</th>
<th>Prix</th>
</tr>
</thead>
<tbody>';
$total_ht = 0;
foreach ($items as $item) {
$product_data = $Products->getProductData($item['product_id']);
$total_ht += (float)$item['amount'];
echo '<tr>
<td>' . esc($product_data['sku']) . '</td>
<td>' . esc($product_data['numero_de_moteur']) . '</td>
<td><input type="text" value="' . esc($product_data['puissance']) . '" style="border:none;width:100%;outline:none;"></td>
<td style="text-align:right;">' . number_format((float)$item['amount'], 2, '.', ' ') . '</td>
</tr>';
}
$tva = $total_ht * 0.2;
$total_ttc = $total_ht + $tva - $order_data['discount'];
echo '</tbody>';
echo ' </table>
<table class="table summary">
<tr><th>Total:</th><td>' . number_format($total_ht, 2, '.', ' ') . '</td></tr>
<tr><th>TVA:</th><td>' . number_format($tva, 2, '.', ' ') . '</td></tr>
<tr><th>Réduction:</th><td>' . number_format($order_data['discount'], 2, '.', ' ') . '</td></tr>
<tr><th>Total à payer:</th><td><strong>' . number_format($total_ttc, 2, '.', ' ') . '</strong></td></tr>
</table>';
echo '<div style="display: flex; justify-content: space-around; margin-top: 5%;">
<div><p style="font-weight:bold;">L\'acheteur</p></div>
<div><p style="font-weight:bold;">Le vendeur</p></div>
</div>';
echo'<div class="invoice-footer">
Merci pour votre commande !<br>
<strong style="color:white;">Original</strong>
</div>';
echo '</div>';
echo '</body>';
echo'</html>';
}
public function print5(int $id)
{
$this->verifyRole('viewOrder');
if (! $id) {
throw new \CodeIgniter\Exceptions\PageNotFoundException();
}
// Modèles
$Orders = new Orders();
$Company = new Company();
$Products = new Products();
$OrderItems = new OrderItems();
// Récupération des données
$order = $Orders->getOrdersData($id);
$items = $OrderItems->getOrdersItemData($id);
$company = $Company->getCompanyData(1);
$today = date('d/m/Y');
// Pré-calculs
$totalTTC = (float) $order['gross_amount'];
$totalHT = $totalTTC / 1.20;
$tva = $totalTTC - $totalHT;
$inWords = $this->numberToWords((int) round($totalTTC));
// Statut paiement
$paidLabel = $order['paid_status'] == 1 ? 'Payé' : 'Non payé';
// Début du HTML
$html = '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Facture '.$order['bill_no'].'</title>
<style>
body { font-family: Arial, sans-serif; font-size:14px; color:#000;margin:0; padding:0; }
.header { display:flex; justify-content:space-between; align-items:center; margin-bottom:20px; }
.header .infos { line-height:1.4; }
.header img { max-height:80px; }
.client { margin-bottom:20px; }
table { width:100%; border-collapse:collapse; margin-bottom:20px; }
th, td { border:1px solid #000; padding:6px; }
th { background:#f0f0f0; }
.right { text-align:right; }
.signature { display:flex; justify-content:space-between; margin-top:50px; }
.signature div { text-align:center; }
.conditions { page-break-before: always; padding:20px; line-height:1.5; }
</style>
</head>
<body onload="window.print()">
<div class="header">
<div class="infos">
<h2 style="margin:0;">'.esc($company['company_name']).'</h2>
<p style="margin:2px 0;"><strong>NIF :</strong> '.esc($company['NIF']).'</p>
<p style="margin:2px 0;"><strong>STAT :</strong> '.esc($company['STAT']).'</p>
<p style="margin:2px 0;"><strong>Contact :</strong> '.esc($company['phone']).' | '.esc($company['phone2']).'</p>
</div>
<div style="text-align:center;">
<img src="'.base_url('assets/images/company_logo.jpg').'" alt="Logo">
<p style="margin:5px 0; font-weight:bold;">Facture N° '.esc($order['bill_no']).'</p>
</div>
</div>
<div class="client">
<p><strong>DOIT Nom :</strong> '.esc($order['customer_name']).'</p>
<p><strong>Adresse :</strong> '.esc($order['customer_address']).'</p>
<p><strong>CIN :</strong> '.esc($order['customer_cin']).'</p>
<p><strong>Téléphone :</strong> '.esc($order['customer_phone'] ?? '').'</p>
<p style="text-align:right;"><em>Antananarivo, le '.$today.'</em></p>
</div>
<table>
<thead>
<tr>
<th>Nom</th>
<th>MARQUE</th>
<th>TYPE</th>
<th>N° Moteur</th>
<th>N° Châssis</th>
<th>Puissance (CC)</th>
<th class="right">PRIX (Ar)</th>
</tr>
</thead>
<tbody>';
foreach ($items as $it) {
$p = $Products->getProductData($it['product_id']);
$Brand = new Brands();
$Category = new Category();
$html .= '
<tr>
<td>'.esc($p['name']).'</td>
<td>'.esc($Brand->getNameById($p['id'])).'</td>
<td>'.esc($Category->getNameById($p['categorie_id'])).'</td>
<td>'.esc($p['numero_de_moteur']).'</td>
<td>'.esc($p['chasis'] ?? '').'</td>
<td>'.esc($p['puissance']).'</td>
<td class="right">'.number_format($p['prix_vente'], 0, '', ' ').'</td>
</tr>';
}
$html .= '
</tbody>
</table>
<table>
<tr>
<td><strong>Prix (HT) :</strong></td>
<td class="right">'.number_format($totalHT, 0, '', ' ').' Ar</td>
</tr>
<tr>
<td><strong>TVA (20%) :</strong></td>
<td class="right">'.number_format($tva, 0, '', ' ').' Ar</td>
</tr>
<tr>
<td><strong>Total (TTC) :</strong></td>
<td class="right">'.number_format($totalTTC, 0, '', ' ').' Ar</td>
</tr>
</table>
<div style="border:1px solid #000; padding:10px; margin-bottom:30px;">
<strong>Arrêté à la somme de :</strong><br>
'.$inWords.'
</div>
<div class="signature">
<div>L\'Acheteur<br><br>__________________</div>
<div>Le Vendeur<br><br>__________________</div>
</div>
<!-- Conditions Générales avec saut de page -->
<div class="conditions">
<div style="display:flex; justify-content:space-between; align-items:center;">
<h3 style="margin:0;">Conditions Générales</h3>
<img src="'.base_url('assets/images/company_logo.jpg').'" alt="Logo" style="height:60px;">
</div>
<ul>
<li>Aucun accessoire (casque, rétroviseur, batterie, etc.) n’est inclus avec la moto. Si le client en a besoin, il doit les acheter séparément.</li>
<li>Le client doit vérifier soigneusement la marchandise avant de quitter notre établissement.</li>
<li>Aucun service après-vente n’est fourni.</li>
<li>La moto est vendue sans garantie, car il s’agit d’un modèle d’occasion.</li>
<li>La facture étant un document provisoire ne peut se substituer au certificat modèle (si requis) délivré au client au moment de l’achat. Il appartient à ce dernier de procéder à l’immatriculation dans le délai prévu par la loi.</li>
</ul>
<div style="text-align:center; margin-top:50px;">L’Acheteur</div>
</div>
</body>
</html>';
return $this->response->setBody($html);
}
/**
* Convertit un nombre entier en texte (français, sans décimales).
* Usage basique, pour Ariary.
*/
private function numberToWords(int $num): string
{
// Cas zéro
if ($num === 0) {
return 'zéro ariary';
}
// Tableaux de base
$units = [
'', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six',
'sept', 'huit', 'neuf', 'dix', 'onze', 'douze',
'treize', 'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf'
];
$tens = [
2 => 'vingt', 3 => 'trente', 4 => 'quarante',
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) {
return $units[$n];
}
if ($n < 100) {
$d = intdiv($n, 10);
$r = $n % 10;
// 70–79 et 90–99
if ($d === 7 || $d === 9) {
$base = $d === 7 ? 60 : 80;
return $tens[$d] . ($r ? '-' . $units[$n - $base] : '');
}
// 20–69 ou 80–89
return $tens[$d] . ($r ? '-' . $units[$r] : '');
}
if ($n < 1000) {
$h = intdiv($n, 100);
$rest = $n % 100;
$hundredText = $h > 1 ? $units[$h] . ' cent' : 'cent';
// « deux cents » prend un « s » si pas de reste
if ($h > 1 && $rest === 0) {
$hundredText .= 's';
}
return $hundredText . ($rest ? ' ' . $convert($rest) : '');
}
if ($n < 1000000) {
$k = intdiv($n, 1000);
$rest = $n % 1000;
$thousandText = $k > 1 ? $convert($k) . ' mille' : 'mille';
return $thousandText . ($rest ? ' ' . $convert($rest) : '');
}
// millions et plus
$m = intdiv($n, 1000000);
$rest = $n % 1000000;
$millionText = $m > 1 ? $convert($m) . ' million' : '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';
}
public function print7(int $id)
{
$this->verifyRole('viewOrder');
if (! $id) {
throw new \CodeIgniter\Exceptions\PageNotFoundException();
}
// Modèles
$Orders = new Orders();
$Company = new Company();
$Products = new Products();
$OrderItems = new OrderItems();
$Brand = new Brands();
$Category = new Category();
// Récupération des données
$order = $Orders->getOrdersData($id);
$items = $OrderItems->getOrdersItemData($id);
$company = $Company->getCompanyData(1);
$today = date('d/m/Y');
// Calculs totaux
$totalTTC = (float) $order['net_amount'];
$totalHT = $totalTTC / 1.20;
$tva = $totalTTC - $totalHT;
$paidLabel = $order['paid_status'] == 1 ? 'Payé' : 'Non payé';
// Démarrage du HTML
$html = '<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Bon de commande '.$order['bill_no'].'</title>
<style>
body { font-family: Arial, sans-serif; font-size:14px; color:#000; margin:0; padding:0; }
.header { display:flex; justify-content:space-between; align-items:center; margin:20px; }
.header .infos { line-height:1.4; }
.header img { max-height:80px; }
.client { margin:20px; }
table { width:calc(100% - 40px); margin:0 20px 20px; border-collapse:collapse; }
th, td { border:1px solid #000; padding:8px; }
th { background:#f0f0f0; }
.right { text-align:right; }
.signature { display:flex; justify-content:space-between; margin:50px 20px 20px; }
.signature div { text-align:center; }
.footer { text-align:center; margin:20px; font-size:12px; color:#666; }
.conditions { page-break-before: always; padding:20px; line-height:1.5; }
@media print {
@page { margin:1cm; }
}
</style>
</head>
<body onload="window.print()">
<div class="header">
<div class="infos">
<h2 style="margin:0;">'.esc($company['company_name']).'</h2>
<p style="margin:2px 0;"><strong>NIF :</strong> '.esc($company['NIF']).'</p>
<p style="margin:2px 0;"><strong>STAT :</strong> '.esc($company['STAT']).'</p>
<p style="margin:2px 0;"><strong>Contact :</strong> '.esc($company['phone']).' | '.esc($company['phone2']).'</p>
</div>
<div style="text-align:center;">
<img src="'.base_url('assets/images/company_logo.jpg').'" alt="Logo">
<p style="margin:5px 0; font-weight:bold;">Bon de commande N° '.esc($order['bill_no']).'</p>
</div>
</div>
<div class="client">
<p><strong>Client :</strong> '.esc($order['customer_name']).'</p>
<p><strong>Adresse :</strong> '.esc($order['customer_address']).'</p>
<p><strong>Téléphone :</strong> '.esc($order['customer_phone']).'</p>
<p><strong>CIN :</strong> '.esc($order['customer_cin']).'</p>
<p style="text-align:right;"><em>Antananarivo, le '.$today.'</em></p>
</div>
<table>
<thead>
<tr>
<th>Nom</th>
<th>Marque</th>
<th>Catégorie</th>
<th>N° Moteur</th>
<th>Châssis</th>
<th>Puissance (CC)</th>
<th class="right">Prix Unitaire (Ar)</th>
</tr>
</thead>
<tbody>';
foreach ($items as $item) {
$p = $Products->getProductData($item['product_id']);
$html .= '<tr>
<td>'.esc($p['name']).'</td>
<td>'.esc($Brand->getNameById($p['brand_id'] ?? $p['id'])).'</td>
<td>'.esc($Category->getNameById($p['categorie_id'])).'</td>
<td>'.esc($p['numero_de_moteur']).'</td>
<td>'.esc($p['chasis'] ?? '').'</td>
<td>'.esc($p['puissance']).'</td>
<td class="right">'.number_format($p['prix_vente'], 0, '', ' ').'</td>
</tr>';
}
$html .= '
</tbody>
</table>
<table style="width:calc(100% - 40px); margin:0 20px 20px;">
<tr>
<td><strong>Total HT :</strong></td>
<td class="right"> Ar</td>
</tr>
<tr>
<td><strong>TVA (20%) :</strong></td>
<td class="right"> Ar</td>
</tr>
<tr>
<td><strong>Total TTC :</strong></td>
<td class="right"> Ar</td>
</tr>
<tr>
<td><strong>Statut :</strong></td>
<td class="right"></td>
</tr>';
if (! empty($order['order_payment_mode'])) {
$html .= '<tr>
<td><strong>Mode de paiement :</strong></td>
<td class="right">'.esc($order['order_payment_mode']).'</td>
</tr>';
}
$html .= '
</table>
<div class="signature">
<div>L\'acheteur<br><br>__________________</div>
<div>Le vendeur<br><br>__________________</div>
</div>
<div class="footer">
Merci pour votre confiance
</div>
<!-- Conditions Générales avec saut de page -->
<div class="conditions">
<div style="display:flex; justify-content:space-between; align-items:center;">
<h3 style="margin:0;">Conditions Générales</h3>
<img src="'.base_url('assets/images/company_logo.jpg').'" alt="Logo" style="height:60px;">
</div>
<ul>
<li>Aucun accessoire (casque, rétroviseur, batterie, etc.) n’est inclus avec la moto. Si le client en a besoin, il doit les acheter séparément.</li>
<li>Le client doit vérifier soigneusement la marchandise avant de quitter notre établissement.</li>
<li>Aucun service après-vente n’est fourni.</li>
<li>La moto est vendue sans garantie, car il s’agit d’un modèle d’occasion.</li>
<li>La facture étant un document provisoire ne peut se substituer au certificat modèle (si requis) délivré au client au moment de l’achat. Il appartient à ce dernier de procéder à l’immatriculation dans le délai prévu par la loi.</li>
</ul>
<div style="text-align:center; margin-top:50px;">L’Acheteur</div>
</div>
</body>
</html>';
// Affichage final
echo $html;
}
public function print31(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();
$Brand = new Brands();
$Category = new Category();
// 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
? "<span style='color: green; font-weight: bold;'>Payé</span>"
: "<span style='color: red; font-weight: bold;'>Non payé</span>";
// STYLE COMMUN avec page-break-after
// --- FACTURES : Une par produit ---
foreach ($items as $item) {
$p = $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;
$inWords = $this->numberToWords((int) round($subtotal));
// Début du document
echo '<!DOCTYPE html>';
echo '<html lang="fr">';
echo '<head><meta charset="utf-8">';
echo '<link rel="stylesheet" href="' . base_url('assets/bower_components/bootstrap/dist/css/bootstrap.min.css') . '">';
echo "<style>
body { font-family: Arial, sans-serif; font-size:14px; color:#000; margin:0; padding:0; }
.header { display:flex; justify-content:space-between; align-items:center; margin-bottom:20px; }
.header .infos { line-height:1.4; }
.header img { max-height:80px; }
.client { margin-bottom:20px; }
table { width:100%; border-collapse:collapse; margin-bottom:20px; }
th, td { border:1px solid #000; padding:6px; text-align:left; }
th { background:#f0f0f0; }
.right { text-align:right; }
.signature { display:flex; justify-content:space-between; margin-top:50px; }
.signature div { text-align:center; }
.page-break { page-break-after: always; }
@media print {
body { font-size: 14px; }
@page { margin: 1cm; }
}
</style>";
echo '</head><body onload="window.print()">';
// Wrapper pour nouvelle page
echo '<div class="page-break">';
// En-tête
echo '<div class="header">';
echo '<div class="infos">';
echo '<h2 style="margin:0;">' . esc($company_info['company_name']) . '</h2>';
echo '<p style="margin:2px 0;"><strong>NIF :</strong> ' . esc($company_info['NIF']) . '</p>';
echo '<p style="margin:2px 0;"><strong>STAT :</strong> ' . esc($company_info['STAT']) . '</p>';
echo '<p style="margin:2px 0;"><strong>Contact :</strong> ' . esc($company_info['phone']) . ' | ' . esc($company_info['phone2']) . '</p>';
echo '<p style="margin:2px 0;"><strong>Magasin :</strong> ' . esc($this->returnStore($order_data['store_id'])) . '</p>';
echo '</div>'; // infos
echo '<div style="text-align:center;">';
echo '<img src="' . base_url('assets/images/company_logo.jpg') . '" alt="Logo">';
echo '<p style="margin:5px 0; font-weight:bold;">Facture N° ' . esc($order_data['bill_no']) . '</p>';
echo '<p style="margin:5px 0;"><em>Antananarivo, le ' . date('d/m/Y') . '</em></p>';
echo '</div>'; // logo
echo '</div>'; // header
// Client
echo '<div class="client">';
echo '<p><strong>Client :</strong> ' . esc($order_data['customer_name']) . '</p>';
echo '<p><strong>Adresse :</strong> ' . esc($order_data['customer_address']) . '</p>';
echo '<p><strong>Téléphone :</strong> ' . esc($order_data['customer_phone']) . '</p>';
echo '<p><strong>CIN :</strong> ' . esc($order_data['customer_cin']) . '</p>';
echo '</div>';
// Tableau produits
echo '<table><thead><tr>';
echo '<th>Nom</th><th>Marque</th><th>Catégorie</th><th>N° Moteur</th><th>Châssis</th><th>Puissance (CC)</th><th class="right">Prix Unit. (Ar)</th>';
echo '</tr></thead><tbody>';
echo '<tr>';
echo '<td>' . esc($p['name']) . '</td>';
echo '<td>' . esc($Brand->getNameById($p['id'])) . '</td>';
echo '<td>' . esc($Category->getNameById($p['categorie_id'])) . '</td>';
echo '<td>' . esc($p['numero_de_moteur']) . '</td>';
echo '<td>' . esc($p['chasis'] ?? '') . '</td>';
echo '<td>' . esc($p['puissance']) . '</td>';
echo '<td class="right">' . number_format($p['prix_vente'], 0, '', ' ') . '</td>';
echo '</tr></tbody></table>';
// Totaux
echo '<table>';
echo '<tr><td><strong>Total HT :</strong></td><td class="right">' . number_format($subtotal, 0, '.', ' ') . ' Ar</td></tr>';
echo '<tr><td><strong>TVA (20%) :</strong></td><td class="right">' . number_format($vatAmount, 0, '.', ' ') . ' Ar</td></tr>';
echo '<tr><td><strong>Réduction :</strong></td><td class="right">' . number_format($discount, 0, '.', ' ') . ' Ar</td></tr>';
echo '<tr><td><strong>Total Net :</strong></td><td class="right">' . number_format($totalNet, 0, '.', ' ') . ' Ar</td></tr>';
echo '<tr><td><strong>Statut :</strong></td><td class="right">' . $paid_status . '</td></tr>';
echo '</table>';
echo '<div style="border:1px solid #000; padding:10px; margin-bottom:30px;">
<strong>Arrêté à la somme de :</strong><br>
'.$inWords.'
</div>';
// Signature
echo '<div class="signature">';
echo '<div>L&#39;Acheteur<br><br>__________________</div>';
echo '<div>Le Vendeur<br><br>__________________</div>';
echo '</div>';
echo '</div>'; // page-break
echo '</body></html>';
}
// --- BON DE COMMANDE : une seule fois après la boucle ---
echo '<!DOCTYPE html>';
echo '<html lang="fr">';
echo '<head><meta charset="utf-8">';
echo '<link rel="stylesheet" href="' . base_url('assets/bower_components/bootstrap/dist/css/bootstrap.min.css') . '">';
echo "<style>
body { font-family: Arial, sans-serif; font-size:14px; color:#000; margin:0; padding:0; }
.header { display:flex; justify-content:space-between; align-items:center; margin-bottom:20px; }
.header .infos { line-height:1.4; }
.header img { max-height:80px; }
.client { margin-bottom:20px; }
table { width:100%; border-collapse:collapse; margin-bottom:20px; }
th, td { border:1px solid #000; padding:6px; text-align:left; }
th { background:#f0f0f0; }
.right { text-align:right; }
.signature { display:flex; justify-content:space-between; margin-top:50px; }
.signature div { text-align:center; }
.page-break { page-break-after: always; }
@media print {
body { font-size: 14px; }
@page { margin: 1cm; }
}
</style>";
echo '</head><body onload="window.print()">';
// Wrapper bon de commande
echo '<div class="page-break">';
echo '<div class="header">';
echo '<div class="infos">';
echo '<h2 style="margin:0;">' . esc($company_info['company_name']) . '</h2>';
echo '<p style="margin:2px 0;"><strong>Commande ID :</strong> ' . esc($order_data['order_no'] ?? $order_data['bill_no']) . '</p>';
echo '<p style="margin:2px 0;"><strong>Magasin :</strong> ' . esc($this->returnStore($order_data['store_id'])) . '</p>';
echo '</div>';
echo '<div style="text-align:center;">';
echo '<img src="' . base_url('assets/images/company_logo.jpg') . '" alt="Logo">';
echo '<p style="margin:5px 0; font-weight:bold;">Bon de commande N° ' . esc($order_data['order_no'] ?? $order_data['bill_no']) . '</p>';
echo '<p style="margin:5px 0;"><em>Antananarivo, le ' . date('d/m/Y') . '</em></p>';
echo '</div>';
echo '</div>'; // header
// Corps bon de commande
echo '<div class="client">';
echo '<p><strong>Client :</strong> ' . esc($order_data['customer_name']) . '</p>';
echo '<p><strong>Adresse :</strong> ' . esc($order_data['customer_address']) . '</p>';
echo '<p><strong>Téléphone :</strong> ' . esc($order_data['customer_phone']) . '</p>';
echo '<p><strong>CIN :</strong> ' . esc($order_data['customer_cin']) . '</p>';
echo '</div>';
echo '<table><thead><tr>';
echo '<th>Nom</th><th>Marque</th><th>Catégorie</th><th>N° Moteur</th><th>Châssis</th><th>Puissance (CC)</th><th class="right">Prix Unit. (Ar)</th>';
echo '</tr></thead><tbody>';
$total_ht = 0;
foreach ($items as $item) {
$p = $Products->getProductData($item['product_id']);
$amount = (float) $item['amount'];
$total_ht += $amount;
echo '<tr>';
echo '<td>' . esc($p['name']) . '</td>';
echo '<td>' . esc($Brand->getNameById($p['id'])) . '</td>';
echo '<td>' . esc($Category->getNameById($p['categorie_id'])) . '</td>';
echo '<td>' . esc($p['numero_de_moteur']) . '</td>';
echo '<td>' . esc($p['chasis'] ?? '') . '</td>';
echo '<td>' . esc($p['puissance']) . '</td>';
echo '<td class="right">' . number_format($amount, 0, '', ' ') . '</td>';
echo '</tr>';
}
$tva = $total_ht * 0.2;
$total_ttc = $total_ht + $tva - (float) $order_data['discount'];
echo '</tbody></table>';
echo '<table>';
echo '<tr><td><strong>Total HT :</strong></td><td class="right">Ar</td></tr>';
echo '<tr><td><strong>TVA :</strong></td><td class="right"> Ar</td></tr>';
echo '<tr><td><strong>Réduction :</strong></td><td class="right">Ar</td></tr>';
echo '<tr><td><strong>Total TTC :</strong></td><td class="right"> Ar</td></tr>';
echo '</table>';
echo '<div class="signature">';
echo '<div>L\'Acheteur<br><br>__________________</div>';
echo '<div>Le Vendeur<br><br>__________________</div>';
echo '</div>';
// --- 3) CONDITIONS GÉNÉRALES (avec rupture AVANT) ---
echo '<div style="page-break-before: always; break-before: page; padding:20px; line-height:1.5;">';
echo '<div style="display:flex; justify-content:space-between; align-items:center;">';
echo '<h3 style="margin:0;">Conditions Générales</h3>';
echo '<img src="' . base_url('assets/images/company_logo.jpg') . '" alt="Moto" style="height:60px;">';
echo '</div>';
echo '<p>* Aucun accessoire (casque, rétroviseur, batterie, etc.) n\'est inclus avec la moto. '
. 'Si le client en a besoin, il doit les acheter séparément.</p>';
echo '<p>* Le client doit s\'assurer de vérifier soigneusement la marchandise avant de quitter notre établissement.</p>';
echo '<p>* Aucun service après-vente n\'est fourni.</p>';
echo '<p>* La moto est vendue sans garantie, car il s\'agit d\'un modèle d\'occasion.</p>';
echo '<p>* La facture étant un document provisoire ne peut se substituer au certificat modèle (si requis) '
. 'délivré au client au moment de l\'achat. Il appartient à ce dernier de procéder à l\'immatriculation '
. 'dans le délai prévu par la loi.</p>';
echo '<div style="text-align:center; margin-top:50px;">L\'Acheteur</div>';
echo '</div>';
echo '</body></html>';
}
}