Correction erreurs, sécurisation code, personnalisation présentation (Jordan)
This commit is contained in:
parent
717fc5320f
commit
4c71100366
19 changed files with 822 additions and 471 deletions
|
|
@ -4,30 +4,8 @@ namespace Paheko;
|
|||
|
||||
require_once __DIR__ . '/_inc.php';
|
||||
|
||||
function toArray($array, $cle, $sep=",")
|
||||
{
|
||||
$result = array();
|
||||
foreach ($array as $elem)
|
||||
{
|
||||
$ro = new \ReflectionObject($elem);
|
||||
$proprietes = $ro->getProperties();
|
||||
$ligne = "";
|
||||
foreach ($proprietes as $p)
|
||||
{
|
||||
if ($p->getName() == $cle) {
|
||||
$key = $p->getValue($elem);
|
||||
}
|
||||
else {
|
||||
$ligne .= $sep . $p->getValue($elem);
|
||||
}
|
||||
}
|
||||
$result[$key] = substr($ligne, strlen($sep));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (!isset($target) || !in_array( $target, ['new', 'edit'])) {
|
||||
throw new Exception('blabla illegal call'); // Fix: exception type?
|
||||
throw new \LogicException('Appel interne invalide du formulaire de document.');
|
||||
} else {
|
||||
$target = ($target === 'new' ? true:false);
|
||||
}
|
||||
|
|
@ -35,7 +13,6 @@ if (!isset($target) || !in_array( $target, ['new', 'edit'])) {
|
|||
$session->requireAccess($session::SECTION_ACCOUNTING, $session::ACCESS_WRITE);
|
||||
|
||||
use Paheko\DB;
|
||||
use stdClass;
|
||||
use const \Paheko\Plugin\Facturation\PATTERNS_LIST;
|
||||
|
||||
$db = DB::getInstance();
|
||||
|
|
@ -69,21 +46,18 @@ if ( !$target ) {
|
|||
throw new UserException("Ce document n'existe pas.");
|
||||
}
|
||||
}
|
||||
if (! $target && $f->archivee)
|
||||
if (!$target && $f->archivee)
|
||||
{
|
||||
throw new UserException("Ce document est archivé, vous n'avez pas le droit de le modifier");
|
||||
}
|
||||
// Traitement
|
||||
// Traitement
|
||||
$data=[];
|
||||
$form->runIf(f('save') && !$form->hasErrors(),
|
||||
function () use ($client, &$data, $form)
|
||||
function () use (&$data, $form)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( count(f('designation')) !== count(f('prix')) )
|
||||
{
|
||||
throw new UserException('Nombre de désignations et de prix reçus différent.');
|
||||
}
|
||||
$type = (int) f('type');
|
||||
|
||||
$data = [
|
||||
'numero' => f('numero_facture'),
|
||||
|
|
@ -93,37 +67,51 @@ $form->runIf(f('save') && !$form->hasErrors(),
|
|||
'archivee' => f('archivee') == 1?1:0,
|
||||
'moyen_paiement' => f('moyen_paiement'),
|
||||
'nom_contact' => f('nom_contact'),
|
||||
'toto' => 0
|
||||
'numero_commande' => f('numero_commande') ?: null,
|
||||
'reference_acheteur' => f('reference_acheteur') ?: null,
|
||||
];
|
||||
$data['type_facture'] = f('type');
|
||||
if (in_array(f('type'), [DEVIS, FACT]))
|
||||
|
||||
$data['type_facture'] = $type;
|
||||
|
||||
if (in_array($type, [DEVIS, FACT], true))
|
||||
{
|
||||
foreach(f('designation') as $k=>$value)
|
||||
$designations = (array) f('designation');
|
||||
$prix = (array) f('prix');
|
||||
|
||||
if (count($designations) !== count($prix))
|
||||
{
|
||||
throw new UserException('Nombre de désignations et de prix reçus différent.');
|
||||
}
|
||||
|
||||
$total = 0;
|
||||
|
||||
foreach($designations as $k=>$value)
|
||||
{
|
||||
if (empty($value) && f('prix')[$k] != null) {
|
||||
throw new UserException("Il manque la désignation de la ligne " . $k+1 . " !!");
|
||||
$prix_ligne = $prix[$k] ?? null;
|
||||
|
||||
if (empty($value) && $prix_ligne !== null && $prix_ligne !== '') {
|
||||
throw new UserException("Il manque la désignation de la ligne " . ($k + 1) . " !!");
|
||||
}
|
||||
elseif ($value != '' && f('prix')[$k] == null) {
|
||||
throw new UserException('Il manque le prix sur la ligne '. $k+1 . ' !!');
|
||||
} elseif (empty($value) && f('prix')[$k] == null) {
|
||||
elseif ($value != '' && ($prix_ligne === null || $prix_ligne === '')) {
|
||||
throw new UserException('Il manque le prix sur la ligne '. ($k + 1) . ' !!');
|
||||
}
|
||||
elseif (empty($value) && ($prix_ligne === null || $prix_ligne === '')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$prix_ligne = Utils::moneyToInteger($prix_ligne);
|
||||
$data['contenu'][$k]['designation'] = $value;
|
||||
$data['contenu'][$k]['prix'] = Utils::moneyToInteger(f('prix')[$k]);
|
||||
$data['toto'] += Utils::moneyToInteger(f('prix')[$k]);
|
||||
$data['contenu'][$k]['prix'] = $prix_ligne;
|
||||
$total += $prix_ligne;
|
||||
}
|
||||
$data['total'] = $data['toto'];
|
||||
unset($data['toto']);
|
||||
|
||||
$data['total'] = $total;
|
||||
|
||||
if (! isset($data['contenu'])) {
|
||||
throw new UserException("Aucune désignation ni aucun prix saisi !!");
|
||||
}
|
||||
if (f('type') == FACT) {
|
||||
$data['numero_commande'] = f('numero_commande');
|
||||
$data['reference_acheteur'] = f('reference_acheteur');
|
||||
}
|
||||
}
|
||||
elseif ( f('type') == CERFA )
|
||||
elseif ($type === CERFA)
|
||||
{
|
||||
$data['moyen_paiement'] = f('moyen_paiement_cerfa');
|
||||
$data['contenu'] = [
|
||||
|
|
@ -131,8 +119,12 @@ $form->runIf(f('save') && !$form->hasErrors(),
|
|||
'nature' => f('nature_don'),
|
||||
'texte' => f('texte_don')];
|
||||
$data['total'] = Utils::moneyToInteger(f('total'));
|
||||
unset($data['toto']);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UserException('Ce type de document doit être créé avec son formulaire dédié.');
|
||||
}
|
||||
|
||||
if (f('base_receveur') == 'client')
|
||||
{
|
||||
$data['receveur_membre'] = 0;
|
||||
|
|
@ -157,18 +149,20 @@ $form->runIf(f('save') && !$form->hasErrors(),
|
|||
}, $csrf_key);
|
||||
|
||||
$form->runIf(f('select_cotis') && !$form->hasErrors(),
|
||||
function () use ($step)
|
||||
function () use (&$step)
|
||||
{
|
||||
$step = true;
|
||||
}, 'add_cotis_1');
|
||||
|
||||
$form->runIf(f('add_cotis') && !$form->hasErrors(),
|
||||
function () use ($radio, $fields, $facture, $form)
|
||||
function () use (&$data, &$radio, $fields, $facture, $form)
|
||||
{
|
||||
$radio['type'] = f('cotisation');
|
||||
try
|
||||
{
|
||||
$num = (int) str_replace('cotis_', '', $radio['type']);
|
||||
$cotis = [];
|
||||
|
||||
foreach($fields as $field)
|
||||
{
|
||||
$cotis[$field] = f($field.'_'.$num);
|
||||
|
|
@ -183,8 +177,12 @@ $form->runIf(f('add_cotis') && !$form->hasErrors(),
|
|||
'receveur_membre' => 1,
|
||||
'receveur_id' => f('membre_cotis'),
|
||||
'date_emission' => f('date_emission'),
|
||||
'date_echeance' => f('date_echeance') ?: f('date_emission'),
|
||||
'reglee' => 1,
|
||||
'archivee' => 0,
|
||||
'moyen_paiement' => 'AU',
|
||||
'total' => $r->paid_amount ?? $r->amount,
|
||||
'nom_contact' => null,
|
||||
'contenu' => ['id' => $cotis['id'],
|
||||
'intitule' => $cotis['label'],
|
||||
'souscription' => $cotis['date'],
|
||||
|
|
@ -264,7 +262,7 @@ if ($target)
|
|||
} // ... s'il est défini dans le document copié
|
||||
elseif (isset($doc['type'])) {
|
||||
$radio['type'] = $doc['type'];
|
||||
} // ... ou par défaut
|
||||
} // ... ou par défaut
|
||||
else
|
||||
{
|
||||
$radio['type'] = FACT;
|
||||
|
|
@ -284,9 +282,9 @@ else
|
|||
|
||||
$doc['date_emission'] = f('date_emission') ?: $f->date_emission;
|
||||
$doc['date_echeance'] = f('date_echeance')?: $f->date_echeance; // Smarty m'a saoulé pour utiliser form_field|date_fr:---
|
||||
$doc['nom_contact'] = $f->nom_contact;
|
||||
$doc['numero_commande'] = $f->numero_commande;
|
||||
$doc['reference_acheteur'] = $f->reference_acheteur;
|
||||
$doc['nom_contact'] = $f->nom_contact ?? null;
|
||||
$doc['numero_commande'] = $f->numero_commande ?? null;
|
||||
$doc['reference_acheteur'] = $f->reference_acheteur ?? null;
|
||||
/* modif DD -- CERFA -------------------------------------- */
|
||||
if ( $f->type_facture == CERFA ) {
|
||||
$doc['total'] = $f->total;
|
||||
|
|
@ -346,11 +344,11 @@ $date->setTimestamp(time());
|
|||
$tpl->assign('date', $date->format('d/m/Y'));
|
||||
|
||||
$tpl->assign(compact('liste', 'radio', 'step', 'designations', 'prix', 'from_user', 'identite', 'csrf_key', 'doc'));
|
||||
$tpl->assign('users', toArray($db->get('SELECT id, '.$identite.' FROM users WHERE id_category != -2 NOT IN (SELECT id FROM users_categories WHERE hidden = 1) ORDER BY ' .$identite. ';'), 'id', " "));
|
||||
$tpl->assign('users', iterator_to_array(Users\Users::iterateAssocByCategory()));
|
||||
$tpl->assign('clients', $db->getAssoc('SELECT id, nom FROM plugin_facturation_clients;'));
|
||||
$tpl->assign('contacts', $db->getAssoc('SELECT id, nom_contact FROM plugin_facturation_clients;'));
|
||||
$tpl->assign('require_number', $require_number);
|
||||
$tpl->assign('number_pattern', PATTERNS_LIST[$plugin->getConfig('pattern')]);
|
||||
$tpl->assign('number_pattern', PATTERNS_LIST[$plugin->getConfig('pattern')] ?? PATTERNS_LIST['']);
|
||||
|
||||
if ($target) {
|
||||
$tpl->display(PLUGIN_ROOT . '/templates/facture_ajouter.tpl');
|
||||
|
|
|
|||
|
|
@ -22,6 +22,42 @@ const PATTERNS_LIST = [
|
|||
'%06{id}' => 'Numéro unique du document sur 6 chiffres ("000042")',
|
||||
];
|
||||
|
||||
function ensureSchemaColumns(): void
|
||||
{
|
||||
$db = \Paheko\DB::getInstance();
|
||||
|
||||
$tables = [
|
||||
'plugin_facturation_clients' => [
|
||||
'siret' => 'siret TEXT',
|
||||
'telephone' => 'telephone TEXT',
|
||||
'email' => 'email TEXT',
|
||||
'nom_contact' => 'nom_contact TEXT',
|
||||
'note' => 'note TEXT',
|
||||
],
|
||||
'plugin_facturation_factures' => [
|
||||
'nom_contact' => 'nom_contact TEXT',
|
||||
'numero_commande' => 'numero_commande TEXT',
|
||||
'reference_acheteur' => 'reference_acheteur TEXT',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($tables as $table => $columns) {
|
||||
$schema = $db->getTableSchema($table);
|
||||
|
||||
if (!$schema) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($columns as $column => $definition) {
|
||||
if (!isset($schema['columns'][$column])) {
|
||||
$db->exec(sprintf('ALTER TABLE %s ADD COLUMN %s;', $db->quoteIdentifier($table), $definition));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ensureSchemaColumns();
|
||||
|
||||
$client = new Client;
|
||||
$facture = new Facture;
|
||||
|
||||
|
|
@ -63,7 +99,7 @@ $tpl->register_function('money_fac', function (array $params)
|
|||
$current_value = htmlspecialchars($current_value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
$currency = Config::getInstance()->get('monnaie');
|
||||
$currency = Config::getInstance()->get('currency');
|
||||
return sprintf('<td><nobr><input type="text" pattern="[0-9]*([.,][0-9]{1,2})?" inputmode="decimal" size="8" class="money" style="width: 60%%" onchange="updateSum();" name="%s" value="%s" /><b>%s</b></nobr></td>', $name, $current_value, $currency);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ $id = (int) qg('id');
|
|||
|
||||
$c = $client->get($id);
|
||||
|
||||
if (!$client)
|
||||
if (!$c)
|
||||
{
|
||||
throw new UserException("Ce client n'existe pas.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,17 @@ $champsPaheko = DynamicFields::getInstance()->listAssocNames();
|
|||
$champsPaheko = array('' => '- Choisir un champ -') + $champsPaheko;
|
||||
|
||||
$form->runIf('save', function () use ($plugin) {
|
||||
$invoice_theme = f('invoice_theme') ?: 'modern';
|
||||
$invoice_accent_color = trim(f('invoice_accent_color') ?: '#4656A5');
|
||||
|
||||
if (!in_array($invoice_theme, ['modern', 'classic', 'minimal'], true)) {
|
||||
throw new UserException('Le style de facture sélectionné est invalide.');
|
||||
}
|
||||
|
||||
if (!preg_match('/^#[0-9A-Fa-f]{6}$/', $invoice_accent_color)) {
|
||||
throw new UserException('La couleur d\'accent doit être au format hexadécimal, par exemple #4656A5.');
|
||||
}
|
||||
|
||||
$plugin->setConfigProperty('rna_asso', trim(f('rna_asso')));
|
||||
$plugin->setConfigProperty('siret_asso', trim(f('siret_asso')));
|
||||
$plugin->setConfigProperty('ttc', (bool) f('ttc'));
|
||||
|
|
@ -22,6 +33,14 @@ $form->runIf('save', function () use ($plugin) {
|
|||
|
||||
$plugin->setConfigProperty('logo', (bool)f('logo'));
|
||||
$plugin->setConfigProperty('footer', f('footer'));
|
||||
$plugin->setConfigProperty('invoice_theme', $invoice_theme);
|
||||
$plugin->setConfigProperty('invoice_accent_color', strtoupper($invoice_accent_color));
|
||||
$plugin->setConfigProperty('invoice_note', trim(f('invoice_note') ?: ''));
|
||||
$plugin->setConfigProperty('payment_terms', trim(f('payment_terms') ?: ''));
|
||||
$plugin->setConfigProperty('invoice_show_status', (bool) f('invoice_show_status'));
|
||||
$plugin->setConfigProperty('invoice_show_address_borders', (bool) f('invoice_show_address_borders'));
|
||||
$plugin->setConfigProperty('invoice_show_email', (bool) f('invoice_show_email'));
|
||||
$plugin->setConfigProperty('invoice_show_web', (bool) f('invoice_show_web'));
|
||||
|
||||
$plugin->setConfigProperty('adresse_client', f('adresse_client'));
|
||||
$plugin->setConfigProperty('code_postal_client', f('code_postal_client'));
|
||||
|
|
@ -36,8 +55,21 @@ $form->runIf('save', function () use ($plugin) {
|
|||
|
||||
|
||||
$tpl->assign('ok', qg('ok') !== null);
|
||||
$tpl->assign('conf', $plugin->getConfig());
|
||||
$conf = $plugin->getConfig();
|
||||
|
||||
foreach (['invoice_show_status', 'invoice_show_address_borders', 'invoice_show_email', 'invoice_show_web'] as $key) {
|
||||
if (!isset($conf->$key)) {
|
||||
$conf->$key = true;
|
||||
}
|
||||
}
|
||||
|
||||
$tpl->assign('conf', $conf);
|
||||
$tpl->assign('patterns', \Paheko\Plugin\Facturation\PATTERNS_LIST);
|
||||
$tpl->assign('champsPaheko', $champsPaheko);
|
||||
$tpl->assign('invoice_themes', [
|
||||
'modern' => 'Moderne',
|
||||
'classic' => 'Classique',
|
||||
'minimal' => 'Minimal',
|
||||
]);
|
||||
|
||||
$tpl->display(PLUGIN_ROOT . '/templates/config.tpl');
|
||||
|
|
|
|||
|
|
@ -12,11 +12,13 @@ $id = (int) qg('id');
|
|||
|
||||
$f = $facture->get($id);
|
||||
|
||||
if (!$client)
|
||||
if (!$f)
|
||||
{
|
||||
throw new UserException("Ce document n'existe pas.");
|
||||
}
|
||||
|
||||
$csrf_key = 'delete_doc_' . $f->id;
|
||||
|
||||
$form->runIf(f('delete') && !$form->hasErrors(),
|
||||
function () use ($facture, $f, $form)
|
||||
{
|
||||
|
|
@ -28,7 +30,8 @@ $form->runIf(f('delete') && !$form->hasErrors(),
|
|||
{
|
||||
$form->addError($e->getMessage());
|
||||
}
|
||||
});
|
||||
}, $csrf_key);
|
||||
|
||||
$tpl->assign('doc', $f);
|
||||
$tpl->assign(compact('csrf_key'));
|
||||
$tpl->display(PLUGIN_ROOT . '/templates/facture_supprimer.tpl');
|
||||
|
|
|
|||
733
admin/pdf.php
733
admin/pdf.php
|
|
@ -4,11 +4,27 @@ namespace Paheko;
|
|||
|
||||
require_once __DIR__ . '/_inc.php';
|
||||
$session->requireAccess($session::SECTION_ACCOUNTING, $session::ACCESS_READ);
|
||||
$users = new Users\Users;
|
||||
|
||||
f(['id' => 'required|numeric']);
|
||||
$id = (int) qg('id');
|
||||
$sign_tag = UserTemplate\Functions::signature();
|
||||
$h = static function ($value): string {
|
||||
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||||
};
|
||||
$br = static function ($value) use ($h): string {
|
||||
return nl2br($h($value));
|
||||
};
|
||||
$format_identifier = static function ($value) use ($h): string {
|
||||
$value = preg_replace('/\s+/', '', (string) $value);
|
||||
return $value !== '' ? $h(implode(' ', str_split($value, 3))) : '';
|
||||
};
|
||||
$detail_line = static function (string $label, $value) use ($h, $br): string {
|
||||
if ($value === null || trim((string) $value) === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return sprintf('<div><span>%s</span>%s</div>', $h($label), $br($value));
|
||||
};
|
||||
|
||||
// Vérification que le document existe
|
||||
if (!$f = $facture->get($id))
|
||||
|
|
@ -18,47 +34,42 @@ if (!$f = $facture->get($id))
|
|||
|
||||
$moyen_paiement = $facture->getMoyenPaiement($f->moyen_paiement);
|
||||
|
||||
// Récupération infos membre
|
||||
try
|
||||
// Récupération infos membre/client dans un objet normalisé pour le rendu
|
||||
if ($f->receveur_membre)
|
||||
{
|
||||
if ($f->receveur_membre)
|
||||
{
|
||||
$c = $users->get($f->receveur_id);
|
||||
// l'identité du membre peut être redéfinie dans la configuration des membres
|
||||
$name_fields = \Paheko\Users\DynamicFields::getNameFields();
|
||||
array_walk($name_fields, function(&$elem) use ($c) {
|
||||
$elem = $c->$elem;
|
||||
});
|
||||
$nom_client = implode(" ", $name_fields);
|
||||
if (preg_match('/^ +$/', $nom_client)) {
|
||||
$nom_client = "** ABSENT **";
|
||||
}
|
||||
$user = Users\Users::get($f->receveur_id);
|
||||
|
||||
// adresse, code postal et ville peuvent être redéfini(e)s dans la configuration du plugin
|
||||
$adresse_client = $plugin->getConfig('adresse_client');
|
||||
if ($adresse_client != null && $c->$adresse_client != null) { $c->adresse = $c->$adresse_client; }
|
||||
$code_postal_client = $plugin->getConfig('code_postal_client');
|
||||
if ($code_postal_client != null && $c->$code_postal_client != null) { $c->code_postal = $c->$code_postal_client; }
|
||||
$ville_client = $plugin->getConfig('ville_client');
|
||||
if ($ville_client != null && $c->$ville_client != null) { $c->ville = $c->$ville_client; }
|
||||
if (!$user) {
|
||||
throw new UserException("Ce membre n'existe plus.");
|
||||
}
|
||||
|
||||
foreach(['ville','code_postal','adresse'] as $v)
|
||||
{
|
||||
if($c->$v == '')
|
||||
{
|
||||
$c->$v = '[À RENSEIGNER DANS LA FICHE MEMBRE]';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$c = $client->get($f->receveur_id);
|
||||
$nom_client = $c->nom;
|
||||
}
|
||||
$nom_client = Users\DynamicFields::getNameFromArray($user) ?: '** ABSENT **';
|
||||
$user_fields = Users\DynamicFields::getInstance()->listAssocNames();
|
||||
$get_user_field = static function (?string $configured, string $fallback) use ($user, $user_fields) {
|
||||
$field = $configured ?: $fallback;
|
||||
return array_key_exists($field, $user_fields) ? ($user->$field ?? null) : null;
|
||||
};
|
||||
|
||||
$c = (object) [
|
||||
'nom' => $nom_client,
|
||||
'adresse' => $get_user_field($plugin->getConfig('adresse_client'), 'adresse') ?: '[À RENSEIGNER DANS LA FICHE MEMBRE]',
|
||||
'code_postal' => $get_user_field($plugin->getConfig('code_postal_client'), 'code_postal') ?: '[À RENSEIGNER]',
|
||||
'ville' => $get_user_field($plugin->getConfig('ville_client'), 'ville') ?: '[À RENSEIGNER]',
|
||||
'siret' => null,
|
||||
'email' => Users\DynamicFields::getFirstEmailField() ? ($user->{Users\DynamicFields::getFirstEmailField()} ?? null) : null,
|
||||
'telephone' => null,
|
||||
];
|
||||
}
|
||||
catch(UserException $e)
|
||||
else
|
||||
{
|
||||
$form->addError($e);
|
||||
$client_data = $client->get($f->receveur_id);
|
||||
|
||||
if (!$client_data) {
|
||||
throw new UserException("Ce client n'existe plus.");
|
||||
}
|
||||
|
||||
$nom_client = $client_data->nom;
|
||||
$c = $client_data;
|
||||
}
|
||||
|
||||
// Formatage dates
|
||||
|
|
@ -74,307 +85,417 @@ if (isset($f->date_echeance))
|
|||
// Génération factures, devis et cotisation
|
||||
if ($f->type_facture != CERFA)
|
||||
{
|
||||
switch ($f->type_facture)
|
||||
{
|
||||
case FACT:
|
||||
$doc = 'Facture n° '. $f->numero;
|
||||
$txtemis = $doc . " - Émise le " . $emission;
|
||||
$txtdest = "Adressée à :";
|
||||
break;
|
||||
case DEVIS:
|
||||
$doc = 'Devis n° '. $f->numero;
|
||||
$txtemis = $doc . " - Émis le " . $emission;
|
||||
$txtdest = "Adressé à :";
|
||||
break;
|
||||
case COTIS:
|
||||
$doc = 'Reçu de cotisation n° '. $f->numero;
|
||||
$txtemis = $doc . " - Émis le " . $emission;
|
||||
$txtdest = "Adressé à :";
|
||||
break;
|
||||
}
|
||||
|
||||
// utiliser l'adresse configurée dans le plugin sinon celle de l'asso sinon rien !
|
||||
if ($plugin->getConfig('rue_asso') != null &&
|
||||
$plugin->getConfig('cp_asso') != null &&
|
||||
$plugin->getConfig('ville_asso') != null)
|
||||
{
|
||||
$adresse =
|
||||
(($plugin->getConfig('numero_rue_asso') != null) ? $plugin->getConfig('numero_rue_asso') . " " : "") .
|
||||
$plugin->getConfig('rue_asso') . "<br>" .
|
||||
$plugin->getConfig('cp_asso') . " " .
|
||||
$plugin->getConfig('ville_asso');
|
||||
}
|
||||
else if ($config->get('org_address') != null)
|
||||
{
|
||||
$adresse = str_replace("\n", '<br>', $config->get('org_address'));
|
||||
}
|
||||
else {
|
||||
$adresse = "";
|
||||
}
|
||||
|
||||
$logo='';
|
||||
if ($plugin->getConfig('logo')) {
|
||||
$logo = '<img id="logo" src="' . $config->fileURL('logo') . '" />';
|
||||
}
|
||||
$asso =
|
||||
// 'Émis par :<br><br>'.
|
||||
'<b>'.$config->get('org_name')."</b><br>".
|
||||
$adresse ."<br>".
|
||||
(($t = $plugin->getConfig('rna_asso'))?"RNA : $t<br>":'').
|
||||
(($t = $plugin->getConfig('siret_asso'))?"SIRET : " . implode(' ', str_split($t, 3)) . "<br>":'').
|
||||
(($t = $config->get('email_asso'))?"Email : $t<br>":'').
|
||||
(($t = $config->get('site_asso'))?"Site web : $t<br>":'');
|
||||
|
||||
$receveur =
|
||||
$txtdest.'<br>'.
|
||||
'<b>'.$nom_client.'</b><br>'.
|
||||
(($t = $f->nom_contact)?"Contact : $t<br>":'').
|
||||
$c->adresse."<br>".
|
||||
$c->code_postal.' '.$c->ville."<br>".
|
||||
(($t = $c->siret)?"SIREN/SIRET : " . implode(' ', str_split($t, 3)) . "<br>":'').
|
||||
(($t = $c->email)?"Email : $t<br>":'').
|
||||
(($t = $c->telephone)?"Tel : $t<br>":'');
|
||||
if ($f->type_facture == FACT) {
|
||||
$receveur .=
|
||||
(($t = $f->numero_commande)?"Commande N° : $t<br>":'').
|
||||
(($t = $f->reference_acheteur)?"Référence : $t<br>":'');
|
||||
}
|
||||
$labels = [
|
||||
FACT => ['Facture', 'Émise le', 'Adressée à', 'Échéance de paiement'],
|
||||
DEVIS => ['Devis', 'Émis le', 'Adressé à', 'Échéance du devis'],
|
||||
COTIS => ['Reçu de cotisation', 'Émis le', 'Adressé à', 'Date du reçu'],
|
||||
];
|
||||
[$document_label, $emission_label, $recipient_label, $due_label] = $labels[$f->type_facture] ?? $labels[FACT];
|
||||
$doc = sprintf('%s n° %s', $document_label, $f->numero);
|
||||
$theme = $plugin->getConfig('invoice_theme') ?: 'modern';
|
||||
$theme = in_array($theme, ['modern', 'classic', 'minimal'], true) ? $theme : 'modern';
|
||||
$accent = $plugin->getConfig('invoice_accent_color') ?: '#4656A5';
|
||||
$accent = preg_match('/^#[0-9A-Fa-f]{6}$/', $accent) ? $accent : '#4656A5';
|
||||
$show_address_borders = $plugin->getConfig('invoice_show_address_borders') !== false;
|
||||
$show_email = $plugin->getConfig('invoice_show_email') !== false;
|
||||
$show_web = $plugin->getConfig('invoice_show_web') !== false;
|
||||
$address_border_class = $show_address_borders ? 'invoice-address-borders' : 'invoice-no-address-borders';
|
||||
$currency = $config->get('currency') ?: '€';
|
||||
$total = Utils::money_format($f->total, ',', ' ');
|
||||
$ttc = $plugin->getConfig('ttc') ? 'TTC' : 'HT';
|
||||
|
||||
// Devis et facture
|
||||
if ($f->type_facture != COTIS)
|
||||
{
|
||||
$echeance = ($f->type_facture?'Échéance de paiement':'Échéance du devis')." : ".$echeance;
|
||||
if ($f->type_facture == FACT) {
|
||||
$reglee = !$f->reglee?'Cette facture est en attente de règlement.':'Cette facture a été réglée.';
|
||||
} else {
|
||||
$reglee = "";
|
||||
}
|
||||
$footer = str_replace("\n", '<br>', $plugin->getConfig('footer') ?? '[Pied de page à configurer]');
|
||||
$ttc = $plugin->getConfig('ttc') ? 'TTC':'HT';
|
||||
|
||||
// Génération du contenu de la facture
|
||||
ob_start();
|
||||
echo <<<EOF
|
||||
<div class="h2">
|
||||
<span>Contenu</span> - $doc
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<table class="contenu">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Désignations
|
||||
</th>
|
||||
<th>
|
||||
Prix
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
EOF;
|
||||
|
||||
$i = 1;
|
||||
foreach($f->contenu as $k=>$v)
|
||||
{
|
||||
echo '<tr><td>';
|
||||
echo str_replace("\n", '<br>', $v['designation']);
|
||||
echo '</td><td>';
|
||||
echo Utils::money_format($v['prix'], ',', ' ') .' €';
|
||||
echo '</td></tr>';
|
||||
$i++;
|
||||
}
|
||||
|
||||
echo <<<EOF
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td><b>Total</b><br>Net à payer</td>
|
||||
<td><b>$total €</b><br>({$ttc})</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<footer>
|
||||
<div class="h2"><span>Détails</span></div>
|
||||
<hr>
|
||||
|
||||
$echeance <br>
|
||||
$reglee
|
||||
Moyen de paiement : $moyen_paiement
|
||||
<p>
|
||||
$footer
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
EOF;
|
||||
if ($f->type_facture == DEVIS) {
|
||||
echo <<<EOF
|
||||
<p><b>Bon pour accord, date et signature<b></p>
|
||||
EOF;
|
||||
}
|
||||
|
||||
$content = ob_get_clean();
|
||||
|
||||
if ($plugin->getConfig('rue_asso') && $plugin->getConfig('cp_asso') && $plugin->getConfig('ville_asso')) {
|
||||
$adresse = trim(($plugin->getConfig('numero_rue_asso') ? $plugin->getConfig('numero_rue_asso') . ' ' : '') . $plugin->getConfig('rue_asso'))
|
||||
. "\n" . $plugin->getConfig('cp_asso') . ' ' . $plugin->getConfig('ville_asso');
|
||||
}
|
||||
else // Reçu de cotisation
|
||||
{
|
||||
$lieu = $plugin->getConfig('ville_asso');
|
||||
else {
|
||||
$adresse = $config->get('org_address_public') ?: $config->get('org_address') ?: '';
|
||||
}
|
||||
|
||||
$logo = '';
|
||||
if ($plugin->getConfig('logo') && ($logo_url = $config->fileURL('logo'))) {
|
||||
$logo = sprintf('<img class="logo" src="%s" alt="" />', $h($logo_url));
|
||||
}
|
||||
|
||||
$asso_details = '<strong>' . $h($config->get('org_name')) . '</strong>';
|
||||
$asso_details .= $adresse ? '<p>' . $br($adresse) . '</p>' : '';
|
||||
$asso_details .= ($t = $plugin->getConfig('rna_asso')) ? $detail_line('RNA', $t) : '';
|
||||
$asso_details .= ($t = $plugin->getConfig('siret_asso')) ? '<div><span>SIRET</span>' . $format_identifier($t) . '</div>' : '';
|
||||
$asso_details .= $show_email && ($t = $config->get('org_email')) ? $detail_line('Email', $t) : '';
|
||||
$asso_details .= ($t = $config->get('org_phone')) ? $detail_line('Tel.', $t) : '';
|
||||
$asso_details .= $show_web && ($t = $config->get('org_web')) ? $detail_line('Web', $t) : '';
|
||||
$brand_summary = '<div class="brand-summary">' . $logo . '<strong>' . $h($config->get('org_name')) . '</strong></div>';
|
||||
|
||||
$receveur = '<strong>' . $h($nom_client) . '</strong>';
|
||||
$receveur .= ($t = ($f->nom_contact ?? null)) ? $detail_line('Contact', $t) : '';
|
||||
$receveur .= '<p>' . $br($c->adresse ?? '') . '<br>' . $h(trim(($c->code_postal ?? '') . ' ' . ($c->ville ?? ''))) . '</p>';
|
||||
$receveur .= ($t = $c->siret ?? null) ? '<div><span>SIREN/SIRET</span>' . $format_identifier($t) . '</div>' : '';
|
||||
$receveur .= $show_email && ($t = $c->email ?? null) ? $detail_line('Email', $t) : '';
|
||||
$receveur .= ($t = $c->telephone ?? null) ? $detail_line('Tel.', $t) : '';
|
||||
$receveur .= $f->type_facture == FACT && ($t = ($f->numero_commande ?? null)) ? $detail_line('Commande', $t) : '';
|
||||
$receveur .= $f->type_facture == FACT && ($t = ($f->reference_acheteur ?? null)) ? $detail_line('Référence', $t) : '';
|
||||
|
||||
if ($f->type_facture != COTIS) {
|
||||
$rows = '';
|
||||
|
||||
foreach($f->contenu as $v) {
|
||||
$rows .= sprintf(
|
||||
'<tr><td class="designation">%s</td><td class="amount">%s %s</td></tr>',
|
||||
$br($v['designation']),
|
||||
$h(Utils::money_format($v['prix'], ',', ' ')),
|
||||
$h($currency)
|
||||
);
|
||||
}
|
||||
|
||||
$payment_terms = trim((string) ($plugin->getConfig('payment_terms') ?: ''));
|
||||
$invoice_note = trim((string) ($plugin->getConfig('invoice_note') ?: ''));
|
||||
$status = '';
|
||||
|
||||
if ($plugin->getConfig('invoice_show_status') && $f->type_facture == FACT) {
|
||||
$status_class = $f->reglee ? 'paid' : 'pending';
|
||||
$status_label = $f->reglee ? 'Facture réglée' : 'En attente de règlement';
|
||||
$status = sprintf('<p class="status %s">%s</p>', $status_class, $h($status_label));
|
||||
}
|
||||
|
||||
$approval = $f->type_facture == DEVIS ? '<section class="approval"><strong>Bon pour accord</strong><span>Date, nom et signature</span></section>' : '';
|
||||
$note = $invoice_note !== '' ? '<p class="invoice-note">' . $br($invoice_note) . '</p>' : '';
|
||||
$terms = $payment_terms !== '' ? $detail_line('Conditions', $payment_terms) : '';
|
||||
$footer = $br($plugin->getConfig('footer') ?? '[Pied de page à configurer]');
|
||||
$echeance_html = $detail_line($due_label, $echeance ?? '');
|
||||
$moyen_html = $detail_line('Moyen de paiement', $moyen_paiement);
|
||||
|
||||
$content = <<<HTML
|
||||
<section class="items">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Désignation</th>
|
||||
<th class="amount">Montant</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
$rows
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section class="summary">
|
||||
<div class="details">
|
||||
$echeance_html
|
||||
$terms
|
||||
$moyen_html
|
||||
$status
|
||||
</div>
|
||||
<div class="total">
|
||||
<span>Total $ttc</span>
|
||||
<strong>$total {$h($currency)}</strong>
|
||||
<em>Net à payer</em>
|
||||
</div>
|
||||
</section>
|
||||
$note
|
||||
$approval
|
||||
<footer>$footer</footer>
|
||||
HTML;
|
||||
}
|
||||
else {
|
||||
$lieu = $plugin->getConfig('ville_asso') ?: '';
|
||||
$intitule = $f->contenu['intitule'];
|
||||
|
||||
$souscription = date('d/m/Y', strtotime($f->contenu['souscription']));
|
||||
$expiration = $f->contenu['expiration'] == '1970-01-01'
|
||||
? "le jour même, s'agissant d'une cotisation ponctuelle"
|
||||
: 'le ' . date('d/m/Y', strtotime($f->contenu['expiration']));
|
||||
$footer = $br($plugin->getConfig('footer') ?? '');
|
||||
|
||||
if($f->contenu['expiration'] == '1970-01-01')
|
||||
{
|
||||
$expiration = "jour même, s'agissant d'une cotisation ponctuelle.";
|
||||
}
|
||||
else {
|
||||
$expiration = date('d/m/Y', strtotime($f->contenu['expiration']));
|
||||
}
|
||||
|
||||
// Génération du contenu du reçu de cotisation
|
||||
$content = <<<EOF
|
||||
<div class="h2">
|
||||
<span>Reçu de votre cotisation</span> - $doc
|
||||
</div>
|
||||
<hr>
|
||||
<div class="contenuTexte">
|
||||
<p>À $lieu, le $emission,</p>
|
||||
$content = <<<HTML
|
||||
<section class="letter">
|
||||
<p>À {$h($lieu)}, le {$h($emission)},</p>
|
||||
<p>Bonjour,</p>
|
||||
|
||||
<p>Nous accusons réception de votre cotisation « $intitule » reçue le $emission et nous vous en remercions.</p>
|
||||
<p>Nous reconnaissons que vous avez acquitté la somme de {$total} €.<br>111
|
||||
Votre adhésion sera donc effective à compter du $souscription jusqu’au $expiration.</p>
|
||||
<br>
|
||||
|
||||
<p>Nous vous prions de recevoir, chère adhérente, cher adhérent, nos meilleures salutations,</p>
|
||||
<br>
|
||||
<p>-représentant·e de l'asso-</p>
|
||||
<br>
|
||||
<p><i>Nous vous rappelons que la cotisation n’est pas soumise à la TVA et qu’elle ne donne pas lieu à la délivrance d’une facture. Elle n’ouvre pas droit au bénéfice des dispositions des articles 200, 238 bis et 885-0 V bis A du code général des impôts.</i></p>
|
||||
</div>
|
||||
EOF;
|
||||
<p>Nous accusons réception de votre cotisation « {$h($intitule)} » reçue le {$h($emission)} et nous vous en remercions.</p>
|
||||
<p>Nous reconnaissons que vous avez acquitté la somme de <strong>{$h($total)} {$h($currency)}</strong>. Votre adhésion sera donc effective à compter du {$h($souscription)} jusqu'à {$h($expiration)}.</p>
|
||||
<p>Nous vous prions de recevoir nos meilleures salutations.</p>
|
||||
<p><strong>Pour {$h($config->get('org_name'))}</strong></p>
|
||||
<p class="legal">Nous vous rappelons que la cotisation n'est pas soumise à la TVA et qu'elle ne donne pas lieu à la délivrance d'une facture. Elle n'ouvre pas droit au bénéfice des dispositions des articles 200, 238 bis et 885-0 V bis A du code général des impôts.</p>
|
||||
</section>
|
||||
<footer>$footer</footer>
|
||||
HTML;
|
||||
}
|
||||
|
||||
//-- Layout du document
|
||||
$html_title = $h($doc . '_' . $emission);
|
||||
$doc_html = $h($doc);
|
||||
$txtemis = $h($emission_label . ' ' . $emission);
|
||||
$txtdest = $h($recipient_label);
|
||||
|
||||
ob_start();
|
||||
echo <<<EOF
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html class="invoice-theme-$theme $address_border_class">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{$doc}_{$emission}</title>
|
||||
<title>$html_title</title>
|
||||
<style>
|
||||
@page {
|
||||
size: A4 portrait;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@page { size: A4 portrait; margin: 14mm; }
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
padding: 4mm;
|
||||
font-family: Helvetica, Arial, sans;
|
||||
margin: 0;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
background: white;
|
||||
line-height: 1.45;
|
||||
color: #20242A;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.titre {
|
||||
text-align: center;
|
||||
font-size: 8pt;
|
||||
margin-bottom: 6mm;
|
||||
margin-top: 0mm;
|
||||
.invoice {
|
||||
display: block;
|
||||
padding-bottom: 28mm;
|
||||
page-break-after: avoid;
|
||||
break-after: avoid-page;
|
||||
}
|
||||
.h2 {
|
||||
margin: 20px 20px 0px 20px;
|
||||
}
|
||||
.h2 span {
|
||||
font-weight: bold;
|
||||
font-size: 14pt;
|
||||
}
|
||||
hr {
|
||||
margin: 5px 0px 15px 0px;
|
||||
border: none;
|
||||
border-top: 1px solid;
|
||||
}
|
||||
.adressage {
|
||||
font-size: 11pt;
|
||||
margin: auto;
|
||||
}
|
||||
.adressage td {
|
||||
width: 40%;
|
||||
vertical-align: top;
|
||||
}
|
||||
.adressage td#logo {
|
||||
width: 20%;
|
||||
vertical-align: top;
|
||||
}
|
||||
.adressage img#logo {
|
||||
height : 3cm;
|
||||
}
|
||||
|
||||
.contenuTexte {
|
||||
padding: 0 6mm;
|
||||
}
|
||||
|
||||
.contenu {
|
||||
.hero {
|
||||
display: table;
|
||||
width: 100%;
|
||||
padding-bottom: 10mm;
|
||||
border-bottom: 2px solid $accent;
|
||||
}
|
||||
|
||||
.contenu td, .contenu th {
|
||||
.brand, .document-title {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
padding: 8px 10px;
|
||||
margin : 0px;
|
||||
}
|
||||
.brand { width: 46%; }
|
||||
.document-title { width: 54%; }
|
||||
.brand-summary {
|
||||
display: inline-block;
|
||||
max-width: 72mm;
|
||||
text-align: center;
|
||||
}
|
||||
.logo {
|
||||
display: block;
|
||||
max-width: 34mm;
|
||||
max-height: 24mm;
|
||||
margin: 0 auto 4mm;
|
||||
}
|
||||
.brand-summary strong {
|
||||
display: block;
|
||||
font-size: 10pt;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.document-title {
|
||||
text-align: right;
|
||||
}
|
||||
.document-title h1 {
|
||||
margin: 0 0 2mm;
|
||||
color: $accent;
|
||||
font-size: 19pt;
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
letter-spacing: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.document-title p {
|
||||
margin: 0;
|
||||
color: #566070;
|
||||
}
|
||||
.addresses {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin: 10mm 0 8mm;
|
||||
}
|
||||
.card {
|
||||
display: table-cell;
|
||||
width: 50%;
|
||||
padding: 6mm;
|
||||
vertical-align: top;
|
||||
border: 1px solid #D9DEE8;
|
||||
}
|
||||
.card + .card { border-left: 0; }
|
||||
.card h2 {
|
||||
margin: 0 0 4mm;
|
||||
color: $accent;
|
||||
font-size: 9pt;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.card strong {
|
||||
display: block;
|
||||
margin-bottom: 2mm;
|
||||
font-size: 12pt;
|
||||
}
|
||||
.card p { margin: 2mm 0; }
|
||||
.card div {
|
||||
margin-top: 1.5mm;
|
||||
}
|
||||
.card span {
|
||||
display: inline-block;
|
||||
min-width: 27mm;
|
||||
margin-right: 3mm;
|
||||
color: #687386;
|
||||
}
|
||||
.invoice-no-address-borders .card {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
.invoice-no-address-borders .card + .card {
|
||||
padding-left: 10mm;
|
||||
}
|
||||
.items table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.contenu tr th, .contenu tr td {
|
||||
text-align: right;
|
||||
width: 16%;
|
||||
}
|
||||
.contenu tr td:nth-child(1), .contenu tr th:nth-child(1) {
|
||||
.items th {
|
||||
padding: 4mm 3mm;
|
||||
color: #fff;
|
||||
background: $accent;
|
||||
text-align: left;
|
||||
width: 84%;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.contenu thead tr, .contenu tfoot tr {
|
||||
background-color: #CCE;
|
||||
border: 10px solid black;
|
||||
.items td {
|
||||
padding: 4mm 3mm;
|
||||
border-bottom: 1px solid #E5E8EF;
|
||||
vertical-align: top;
|
||||
}
|
||||
.contenu tbody tr:nth-child(even) {
|
||||
background-color: #DDF !important;
|
||||
.items tr:nth-child(even) td {
|
||||
background: #F7F8FB;
|
||||
}
|
||||
.contenu tfoot {
|
||||
display: table-row-group;
|
||||
.amount {
|
||||
width: 34mm;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
footer {
|
||||
bottom: 0;
|
||||
margin: 14mm 0;
|
||||
width: inherit;
|
||||
.summary {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin-top: 8mm;
|
||||
}
|
||||
.details, .total {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
}
|
||||
.details {
|
||||
width: 64%;
|
||||
color: #3B4350;
|
||||
}
|
||||
.details div {
|
||||
margin-bottom: 2mm;
|
||||
}
|
||||
.details span {
|
||||
display: inline-block;
|
||||
min-width: 42mm;
|
||||
margin-right: 4mm;
|
||||
color: #687386;
|
||||
}
|
||||
.total {
|
||||
width: 36%;
|
||||
padding: 4mm 5mm;
|
||||
color: #fff;
|
||||
background: $accent;
|
||||
text-align: right;
|
||||
}
|
||||
.total span, .total em {
|
||||
display: block;
|
||||
font-style: normal;
|
||||
font-size: 9.5pt;
|
||||
}
|
||||
.total strong {
|
||||
display: block;
|
||||
margin: 1mm 0;
|
||||
font-size: 17pt;
|
||||
line-height: 1.15;
|
||||
}
|
||||
.status {
|
||||
display: inline-block;
|
||||
margin: 2mm 0 0;
|
||||
padding: 1.5mm 3mm;
|
||||
border: 1px solid #D9DEE8;
|
||||
font-weight: 700;
|
||||
}
|
||||
.status.paid { color: #1F6B3A; }
|
||||
.status.pending { color: #9A4D00; }
|
||||
.invoice-note, .approval, .letter {
|
||||
margin-top: 8mm;
|
||||
}
|
||||
.approval {
|
||||
min-height: 25mm;
|
||||
padding-top: 4mm;
|
||||
border-top: 1px solid #D9DEE8;
|
||||
}
|
||||
.approval strong, .approval span {
|
||||
display: block;
|
||||
}
|
||||
.legal {
|
||||
margin-top: 8mm;
|
||||
color: #566070;
|
||||
font-size: 9pt;
|
||||
}
|
||||
footer {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding-top: 6mm;
|
||||
color: #566070;
|
||||
font-size: 8.5pt;
|
||||
text-align: center;
|
||||
border-top: 1px solid #D9DEE8;
|
||||
}
|
||||
.invoice-theme-classic .hero {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
.invoice-theme-classic .items th,
|
||||
.invoice-theme-classic .total {
|
||||
background: #2F343D;
|
||||
}
|
||||
.invoice-theme-minimal .hero,
|
||||
.invoice-theme-minimal .card,
|
||||
.invoice-theme-minimal footer {
|
||||
border-color: #E6E8ED;
|
||||
}
|
||||
.invoice-theme-minimal .items th,
|
||||
.invoice-theme-minimal .total {
|
||||
color: #20242A;
|
||||
background: #F0F2F6;
|
||||
}
|
||||
@media screen {
|
||||
body {
|
||||
padding: 14mm;
|
||||
}
|
||||
footer {
|
||||
right: 14mm;
|
||||
bottom: 14mm;
|
||||
left: 14mm;
|
||||
}
|
||||
}
|
||||
@media print {
|
||||
footer {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="titre">
|
||||
$txtemis
|
||||
</p>
|
||||
|
||||
<table class="adressage">
|
||||
<tr>
|
||||
<td id="logo">$logo</td>
|
||||
<td>$asso</td>
|
||||
<td>$receveur</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
$content
|
||||
<main class="invoice">
|
||||
<header class="hero">
|
||||
<section class="brand">
|
||||
$brand_summary
|
||||
</section>
|
||||
<section class="document-title">
|
||||
<h1>$doc_html</h1>
|
||||
<p>$txtemis</p>
|
||||
</section>
|
||||
</header>
|
||||
<section class="addresses">
|
||||
<div class="card">
|
||||
<h2>Émetteur</h2>
|
||||
$asso_details
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>$txtdest</h2>
|
||||
$receveur
|
||||
</div>
|
||||
</section>
|
||||
$content
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
EOF;
|
||||
|
||||
$html = ob_get_clean();
|
||||
|
||||
HTML;
|
||||
} // Génération du CERFA
|
||||
elseif ($f->type_facture == CERFA)
|
||||
{
|
||||
|
|
@ -394,9 +515,9 @@ elseif ($f->type_facture == CERFA)
|
|||
$t['objet2'] = $plugin->getConfig('objet_2');
|
||||
|
||||
$t['nom'] = $nom_client;
|
||||
$t['adresse'] = $c->adresse;
|
||||
$t['cp'] = $c->code_postal;
|
||||
$t['ville'] = $c->ville;
|
||||
$t['adresse'] = $c->adresse ?? '';
|
||||
$t['cp'] = $c->code_postal ?? '';
|
||||
$t['ville'] = $c->ville ?? '';
|
||||
$t['total'] = '***'.Utils::money_format($f->total).'***';
|
||||
$t['total_lettre'] = numfmt_create('fr_FR', \NumberFormatter::SPELLOUT)->format($f->total/100). ' euros';
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue