[ 'id' => DEVIS, 'accounts' => [], 'label' => 'Devis', 'help' => ''], FACT => [ 'id' => FACT, 'accounts' => [], 'label' => 'Facture', 'help' => ''], CERFA => [ 'id' => CERFA, 'accounts' => [], 'label' => 'Reçu fiscal', 'help' => 'Reçu fiscal pour un don (membre ou client)'], COTIS => [ 'id' => COTIS, 'accounts' => [], 'label' => 'Reçu de cotisation', 'help' => 'Reçu pour une cotisation payée par un·e membre'], ]; public function __construct() { } // Fix : est dépendant de l'ordre des données dans l'array // et implique que toutes les données soient présentes (pas possible de faire un update partiel) public function _checkFields(&$datas) { foreach($datas as $k=>$data) { if (!in_array($k, $this->keys)) { throw new UserException("Clé inattendue : $k."); } if(!is_array($data)){ $datas[$k] = trim($data); } if ($datas[$k] === '') { throw new UserException("La valeur de $k est vide"); } switch($k) { case 'type_facture': if (!array_key_exists($datas[$k], $this->types)) { throw new UserException("$k est de type non-attendue ($data)."); } if ($datas[$k] < 2) { $fac = true; $cerfa = false; $recu = false; } elseif ($datas[$k] == 2) { $fac = false; $cerfa = true; $recu = false; } elseif ($datas[$k] == 3) { $fac = false; $cerfa = false; $recu = true; } break; case 'receveur_membre': case 'reglee': case 'archivee': if ($datas[$k] != 1 && $datas[$k] != 0) { throw new UserException("$k est de valeur non-attendue ($data)."); } break; case 'receveur_id': if (!is_numeric($datas[$k]) || $datas[$k] < 0) { throw new UserException("L'id du receveur est non-attendu ($data)."); } break; case 'date_emission': $datas[$k] = \DateTime::createFromFormat('!d/m/Y', $data)->format('Y-m-d'); break; case 'date_echeance': $datas[$k] = \DateTime::createFromFormat('!d/m/Y', $data)->format('Y-m-d'); if (DateTime::createFromFormat('!Y-m-d', $datas[$k])->format('U') < DateTime::createFromFormat('!Y-m-d', $datas['date_emission'])->format('U')) { throw new UserException("La date d'échéance est antérieure à la date d'émission ($data)."); } break; case 'moyen_paiement': if (!array_key_exists($datas[$k], $this->listMoyensPaiement())) { throw new UserException("Le moyen de paiement ne correspond pas à la liste interne ($data)."); } break; case 'contenu': if ($fac) { if (!is_array($datas[$k]) || empty($datas[$k])) { throw new UserException("Le contenu du document est vide ($data)."); } $total = 0; foreach($datas[$k] as $g => $r) { if (empty($r['designation']) && empty($r['prix'])) { unset($datas[$k][$g]); unset($datas[$k]['prix']); continue; } elseif (empty($r['prix'])) { $datas[$k]['prix'] = 0; } if (!is_int($r['prix'])) { throw new UserException('Un (ou plus) des prix n\'est pas un entier.'); } $total += $r['prix']; } if($fac && !$total) { throw new UserException("Toutes les désignations/prix sont vides."); } } elseif ($cerfa) { } elseif ($recu) { // $fields = ['id', 'intitule', 'date', 'expiration']; // foreach ($datas[$k]as $) } $datas[$k] = json_encode($datas[$k]); break; case 'total': if ($cerfa && $datas[$k] < 1) { throw new UserException('Le total ne peut être inférieur à 1€ pour les reçus (bug encore non résolu).'); } if ($fac && !isset($datas['contenu'])) { throw new UserException("Pas de contenu fourni pour vérifier le total."); } if ($fac && $total != $datas[$k]) { throw new UserException("Les totaux sont différents ($total != $datas[$k]."); } break; } } } public function add($data) { $db = DB::getInstance(); $this->_checkFields($data); if(isset($data['numero']) && $db->test('plugin_facturation_factures', 'numero = ? COLLATE NOCASE', $data['numero'])) { throw new UserException('Un document avec ce numéro existe déjà, hors le numéro doit être unique.'); } $db->insert('plugin_facturation_factures', $data); return $db->lastInsertRowId(); } public function get($id) { $db = DB::getInstance(); $r = $db->first('SELECT * FROM plugin_facturation_factures WHERE id = ? LIMIT 1;', (int)$id); if(!$r) { throw new UserException("Pas de document retournée avec cet id."); } if ($r->contenu) { $r->contenu = json_decode($r->contenu, true); } $r->date_emission = \DateTime::createFromFormat('!Y-m-d', $r->date_emission); if ($r->date_echeance) { $r->date_echeance= \DateTime::createFromFormat('!Y-m-d', $r->date_echeance); } return $r; } public function listAll() { $r = (array)DB::getInstance()->get('SELECT *, strftime(\'%s\', date_emission) AS date_emission, strftime(\'%s\', date_echeance) AS date_echeance FROM plugin_facturation_factures'); foreach ($r as $e) { if($e->contenu) { $e->contenu = json_decode((string)$e->contenu, true); } } return $r; } public function edit($id, $data = []) { $db = DB::getInstance(); $this->_checkFields($data); if(isset($data['numero']) && $db->test('plugin_facturation_factures', 'numero = ? COLLATE NOCASE AND id != ?', $data['numero'], (int)$id)) { throw new UserException('Un document avec ce numéro existe déjà, hors le numéro doit être unique.'); } return $db->update('plugin_facturation_factures', $data, $db->where('id', (int)$id)); } public function listUserDoc($base, $id) { $client = new Client; if ($base == 0) // Si c'est un client { if(!$client->get($id)) { throw new UserException("Ce client n'existe pas."); } } else // Si c'est un membre de l'asso { throw new UserException("Woopsie, g pô encore implémenté l'usage des membres de l'asso comme clients"); } $r = (array)DB::getInstance()->get('SELECT *, strftime(\'%s\', date_emission) AS date_emission, strftime(\'%s\', date_echeance) AS date_echeance FROM plugin_facturation_factures WHERE receveur_membre = ? AND receveur_id = ?', (int)$base, (int)$id); foreach ($r as $e) { if ($e->contenu) { $e->contenu = json_decode((string)$e->contenu, true); } } return empty($r)?false:$r; } public function hasDocs($base, $id) { $client = new Client; if ($base == 0) // Si c'est un client { if(!$client->get($id)) { throw new UserException("Ce client n'existe pas."); } } else // Si c'est un membre de l'asso { throw new UserException("Woopsie, g pô encore implémenté l'usage des membres de l'asso comme clients"); } return DB::getInstance()->test('plugin_facturation_factures', 'receveur_membre = '. $base .' AND receveur_id = '. $id); } // ** Pour type reçu ** public $recu_fields = ['id', 'label', 'amount', 'date', 'expiry', 'paid', 'paid_amount']; public function getCotis(int $user_id, int $su_id = null) { $where = 'WHERE su.id_user = ?'; if (null !== $su_id) { $where .= ' AND su.id = '.$su_id; } $sql = 'SELECT su.id, s.label, su.date, MAX(su.expiry_date) as expiry, sf.label as fee, sf.amount as amount, su.paid, SUM(tl.debit) as paid_amount FROM services_users su INNER JOIN services s ON s.id = su.id_service LEFT JOIN services_fees sf ON sf.id = su.id_fee LEFT JOIN acc_transactions_users tu ON tu.id_service_user = su.id LEFT JOIN acc_transactions_lines tl ON tl.id_transaction = tu.id_transaction '.$where.' GROUP BY su.id ORDER BY su.date;'; return DB::getInstance()->get($sql, $user_id); } public function listMoyensPaiement($assoc = false) { $db = DB::getInstance(); $query = 'SELECT code, nom FROM plugin_facturation_paiement ORDER BY nom COLLATE NOCASE;'; if ($assoc) { return $db->getAssoc($query); } else { return $db->getGrouped($query); } } public function getMoyenPaiement($code) { $db = DB::getInstance(); return $db->firstColumn('SELECT nom FROM plugin_facturation_paiement WHERE code = ?;', $code); } }