Modèles ODT : plusieurs problèmes.

Bonjour,

j’essaye de mettre en page un modèle odt pour l’édition de factures. Dans l’ensemble tout se passe bien, à l’exception de deux points :

  1. Je n’arrive pas à afficher « correctement » le total HT des lignes de facture {line_price_ht} (ex.:152.3). Étrangement, le prix unitaire HT s’affiche "correctement, (ex.: 1520,30). Pour les totaux, j’utilise les nouvelles variables {xxx_locale}, qui fonctionnent très bien. Bien qu’elles ne soient pas renseignée sur le wiki, j’ai tout de même essayé d’ajouter « _locale » aux variables des lignes… C’eut été trop facile, ça ne fonctionne pas.
    J’ai vu sur le forum un post qui décrit le même problème mais il a été solutionné en descendant de version, ce que je ne veux pas faire…
    Et c’est là que j’ai besoin d’aide…

  2. Je ne parviens pas à utiliser les conditions.

[!-- IF {my_var} --] Print this text if {my_var} is true (can be any value but null/0/empty string) [!-- ELSE {my_var} --] Or print this if it's false (null/0/empty string) [!-- ENDIF {my_var} --]
Je remplace bien évidement {my_var} par le nom d’une variable existante. Que j’essaie dans une ligne ou hors des lignes, le test n’est pas effectué et le résultat ressemble à ceci si {my_var}=« Une valeur »:

[!-- IF Une valeur} --] Print this text if Une valeur is true (can be any value but null/0/empty string) [!-- ELSE Une valeur --] Or print this if it's false (null/0/empty string) [!-- ENDIF Une valeur --]
J’ai bien vérifié l’exactitude du code. J’ai essayé avec et sans des retours à la ligne, avec et sans ELSEIF, avec différentes variables, vides ou pas… Rien n’y fait !
Et, de nouveau, c’est ici que j’ai besoin d’aide…

C’est peut-être un/des bug(s)…

Version de Dolibarr 3.5.2 (3.5.0-beta installée et mise à jour en 3.5.2)

D’avance je remercie les bonnes âme qui viendront à mon secours.

Pour le problème de formatage des nombres, j’ai modifié le fichier

htdocs/core/modules/doc/doc_generic_invoice_odt.modules.php
comme suit :
ligne 171:

	/**
	 * Define array with couple substitution key => substitution value
	 *
	 * @param   array		$line			Array of lines
	 * @param   Translate	$outputlangs    Lang object to use for output
	 * @return	array						Return substitution array
	 */
	function get_substitutionarray_lines($line,$outputlangs)
	{
		global $conf;

		return array(
		'line_fulldesc'=>doc_getlinedesc($line,$outputlangs),
		'line_product_ref'=>$line->product_ref,
		'line_product_label'=>$line->product_label,
		'line_desc'=>$line->desc,
		'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits),
		'line_up'=>price($line->subprice, 0, $outputlangs),
		'line_qty'=>$line->qty,
		'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''),
		'line_price_ht'=>price2num($line->total_ht),
		'line_price_ttc'=>price2num($line->total_ttc),
		'line_price_vat'=>price2num($line->total_tva),
		'line_date_start'=>dol_print_date($line->date_start, 'day', false, $outputlangs),
		'line_date_end'=>dol_print_date($line->date_end, 'day', false, $outputlangs),
		);
	}

remplacé par:

	/**
	 * Define array with couple substitution key => substitution value
	 *
	 * @param   array		$line			Array of lines
	 * @param   Translate	$outputlangs    Lang object to use for output
	 * @return	array						Return substitution array
	 */
	function get_substitutionarray_lines($line,$outputlangs)
	{
		global $conf;

		return array(
		'line_fulldesc'=>doc_getlinedesc($line,$outputlangs),
		'line_product_ref'=>$line->product_ref,
		'line_product_label'=>$line->product_label,
		'line_desc'=>$line->desc,
		'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits),
		'line_up'=>price($line->subprice, 0, $outputlangs),
		'line_qty'=>$line->qty,
		'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''),
		'line_price_ht'=>price2num($line->total_ht),
		'line_price_ttc'=>price2num($line->total_ttc),
		'line_price_vat'=>price2num($line->total_tva),
		'line_date_start'=>dol_print_date($line->date_start, 'day', false, $outputlangs),
		'line_date_end'=>dol_print_date($line->date_end, 'day', false, $outputlangs),
		'line_price_ht_locale'=>price($line->total_ht,0,$outputlangs),
		'line_price_ttc_locale'=>price($line->total_ttc,0,$outputlangs),
		'line_price_vat_locale'=>price($line->total_tva,0,$outputlangs),
		);
	}

Ce qui permet d’utiliser les tags suivants dans les lignes de facture:

[ul]
[li]{line_price_ht_locale}[/li]
[li]{line_price_ttc_locale}[/li]
[li]{line_price_vat_locale}[/li][/ul]

Et pour que ça fonctionne aussi pour les propositions, j’ai modifié le fichier:

htdocs/core/class/commondocgenerator.class.php

comme suit:
ligne 293:

[code]
/**
* Define array with couple substitution key => substitution value
*
* @param array $line Array of lines
* @param Translate $outputlangs Lang object to use for output
* @return array Substitution array
*/
function get_substitutionarray_propal_lines($line,$outputlangs)
{
global $conf;

	return array(
	'line_fulldesc'=>doc_getlinedesc($line,$outputlangs),
	'line_product_ref'=>$line->product_ref,
	'line_product_label'=>$line->product_label,
	'line_desc'=>$line->desc,
	'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits),
	'line_up'=>price($line->subprice),
	'line_qty'=>$line->qty,
	'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''),
	'line_price_ht'=>price($line->total_ht),
	'line_price_ttc'=>price($line->total_ttc),
	'line_price_vat'=>price($line->total_tva),
	'line_date_start'=>$line->date_start,
	'line_date_end'=>$line->date_end
	);
}[/code]

remplacé par:

[code]
/**
* Define array with couple substitution key => substitution value
*
* @param array $line Array of lines
* @param Translate $outputlangs Lang object to use for output
* @return array Substitution array
*/
function get_substitutionarray_propal_lines($line,$outputlangs)
{
global $conf;

	return array(
	'line_fulldesc'=>doc_getlinedesc($line,$outputlangs),
	'line_product_ref'=>$line->product_ref,
	'line_product_label'=>$line->product_label,
	'line_desc'=>$line->desc,
	'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits),
	'line_up'=>price($line->subprice),
	'line_qty'=>$line->qty,
	'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''),
	'line_price_ht'=>price($line->total_ht),
	'line_price_ttc'=>price($line->total_ttc),
	'line_price_vat'=>price($line->total_tva),
	'line_price_ht_locale'=>price($line->total_ht,0,$outputlangs),
	'line_price_ttc_locale'=>price($line->total_ttc,0,$outputlangs),
	'line_price_vat_locale'=>price($line->total_tva,0,$outputlangs),
	'line_date_start'=>$line->date_start,
	'line_date_end'=>$line->date_end
	);
}[/code]

Pour le problème des conditions, en me basant sur ce [url=www.dolibarr.fr/forum/t/resolu-symbole-dans-open-office/17490/1 du forum[/url], j’ai modifié le fichier:

htdoc/includes/odtphp/Segment.php
comme suit:
ligne 83:

public function merge() { $this->xmlParsed .= str_replace(array_keys($this->vars), array_values($this->vars), $this->xml); if ($this->hasChildren()) { foreach ($this->children as $child) { $this->xmlParsed = str_replace($child->xml, ($child->xmlParsed=="")?$child->merge():$child->xmlParsed, $this->xmlParsed); $child->xmlParsed = ''; } } $reg = "/\[!--\sBEGIN\s$this->name\s--\](.*)\[!--\sEND\s$this->name\s--\]/sm"; $this->xmlParsed = preg_replace($reg, '$1', $this->xmlParsed); $this->file->open($this->odf->getTmpfile()); foreach ($this->images as $imageKey => $imageValue) { if ($this->file->getFromName('Pictures/' . $imageValue) === false) { // Add the image inside the ODT document $this->file->addFile($imageKey, 'Pictures/' . $imageValue); // Add the image to the Manifest (which maintains a list of images, necessary to avoid "Corrupt ODT file. Repair?" when opening the file with LibreOffice) $this->odf->addImageToManifest($imageValue); } } $this->file->close(); return $this->xmlParsed; }
remplacé par:

[code]
public function merge()
{
$this->xmlParsed .= $this->xml;
foreach($this->vars as $key => $value)
{
dol_syslog(« Zvariable ».$key." « .$value. »/variable");
// If value is true (not 0 nor false nor null nor empty string)
if($value)
{
// Remove the IF tag
$reg = ‹ @[!–\sIF\s › . $key . ‹ \s–]@smU ›;
$this->xmlParsed = preg_replace($reg, ‹  ›, $this->xmlParsed);

			// Remove everything between the ELSE tag (if it exists) and the ENDIF tag
			$reg = '@(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy
			$this->xmlParsed = preg_replace($reg, '', $this->xmlParsed);
		}
		// Else the value is false, then two cases: no ELSE and we're done, or there is at least one place where there is an ELSE clause, then we replace it
		else
		{

			// Find all conditional blocks for this variable: from IF to ELSE and to ENDIF
			$reg = '@\[!--\sIF\s' . $key . '\s--\](.*)(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy

			preg_match_all($reg, $this->xmlParsed, $matches, PREG_SET_ORDER);

			foreach($matches as $match)
			{ // For each match, if there is an ELSE clause, we replace the whole block by the value in the ELSE clause
				dol_syslog("match".$match."/match");
				if (!empty($match[3])) $this->xmlParsed = str_replace($match[0], $match[3], $this->xmlParsed);
			}
			// Cleanup the other conditional blocks (all the others where there were no ELSE clause, we can just remove them altogether)
			$this->xmlParsed = preg_replace($reg, '', $this->xmlParsed);
		}
	}

	$this->xmlParsed = str_replace(array_keys($this->vars), array_values($this->vars), $this->xmlParsed);
	if ($this->hasChildren())
	{
		foreach ($this->children as $child)
		{
			$this->xmlParsed = str_replace($child->xml, ($child->xmlParsed=="")?$child->merge():$child->xmlParsed, $this->xmlParsed);
			$child->xmlParsed = '';
		}
	}
	$reg = "/\[!--\sBEGIN\s$this->name\s--\](.*)\[!--\sEND\s$this->name\s--\]/sm";
	$this->xmlParsed = preg_replace($reg, '$1', $this->xmlParsed);
	$this->file->open($this->odf->getTmpfile());
	foreach ($this->images as $imageKey => $imageValue)
	{
		if ($this->file->getFromName('Pictures/' . $imageValue) === false)
		{
			// Add the image inside the ODT document
			$this->file->addFile($imageKey, 'Pictures/' . $imageValue);
			// Add the image to the Manifest (which maintains a list of images, necessary to avoid "Corrupt ODT file. Repair?" when opening the file with LibreOffice)
			$this->odf->addImageToManifest($imageValue);
		}
	}

	$this->file->close();
	return $this->xmlParsed;
}[/code]

Différence par rapport au code du post cité : la partie « remove the IF tags ».

A première vue ça a l’air de fonctionner, pour des conditions dans et hors des lignes produits, mais n’étant pas du tout développeur, je ne peux rien garantir… :-/

1 « J'aime »

Bonjour,

dans la génération du modèle odt de facture, quand on appelle le texte des conditions de payement {object_payment_term} c’est le code de la condition de payement qui est affiché.

J’ai donc modifié le fichier

htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php
comme suit:
ligne 126:

'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement),
remplacé par:

[code]
‹ object_payment_term ›=>($outputlangs->transnoentitiesnoconv(‹ PaymentCondition ›.$object->cond_reglement_code)!=‹ PaymentCondition ›.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv(‹ PaymentCondition ›.$object->cond_reglement_code):$object->cond_reglement_doc),[/code

Bonjour,

Je déterre ce sujet (pas si vieux), ou plutôt monologue (bravo pour la patiente et l’acharnement !) pour constater qu’en 3.6.2 c’est toujours pareil.

Apparemment, les expressions conditionnelles ne fonctionnent toujours pas et les formats des montants ne sont pas cohérents.

Bug #1855 pour les substitutions conditionnelles et #1856 pour les montants.

À suivre !

1 « J'aime »

Le bug #1855 pour les conditions serait corrigé en 3.6.3.

1 « J'aime »

Bonjour,

Merci pour ces réponses, mais la dernière version stable téléchargeable que je trouve sur sourceforge est la version 3.6.2 et dans les versions beta sur la page de téléchargement, je ne la vois pas non plus…

Je ne peux donc pas tester…

Au temps pour moi… Je viens de la trouver sur github. Mais le site Dolibarr envoie vers sourceforge…

Idem :happy:

Peut-être une version intercalaire à venir avant la 3.7 ?

Par ailleurs, Marcos Garcià essaie de répondre au problème des formats de montants.

Je viens de la trouver sur github, je teste celà.
Question complémentaire : sachant que la version 3.7 est dans les « starting blocks », ces corrections dans la version 3.6 seront aussi présentes dans les versions suivantes ?

Je viens d’essayer la fonction IF en version 3.6.3 sur les devis : ça fonctionne ! Merci !
Par contre, {line_up_locale} toujours pas (je n’ai pas essayé d’autre, ni dans d’autres documents).

En lisant les réponses de Marcos García, je viens d’essayer à nouveau les xxx_locale… Il a entièrement raison : même en tapant le tag en une seul fois dans LibreOffice (dans mon cas), des informations de formatage sont parfois insérées ! Donc deux solutions à mon avis :

  1. « effacer le formatage direct » sur chaque tag
    ou
  2. saisir les tags dans un éditeur de texte « brut » et les copier-coller « sans style » (seule possibilité si l’éditeur est vraiment « brut »)

J’ai essayé la possibilité 2 avec l’ensemble des tags listés par Marcos García et tout passe !

Je ferais des test plus en profondeur sur les différents types de documents et je vous tiendrais informés des résultats.

Grand merci à vous deux donc !

Re-bonjour.

Je viens de pousser les tests sur les conditions un peu plus loin, et je pense qu’il y a un soucis.

Le but est d’utiliser un tableau de produits avec une colonne « Remise » si au moins un produit bénéficie d’une remise, par contre si aucun produit ne bénéficie de remise, le tableau de produit n’affiche pas la colonne « Remise ». (Ca ne sert à rien de « tenter » le client qui ne demande pas de remise…

Pour ce faire, je teste la variable {object_total_discount_ht}, si elle est supérieure à 0 -> tableau avec colonne remise, sinon, tableau sans remise :

[!-- IF {object_total_discount_ht} --]
TABLEAU 1
[!-- ELSE {object_total_discount_ht} --]
TABLEAU 2
[!-- ENDIF {object_total_discount_ht} --]

Si au moins un produit bénéficie d’une remise, le tableau avec la colonne « Remise » est bien affiché, mais avec uniquement la première ligne de produit, peu importe si c’est cette ligne ou une autre qui bénéficie de la remise.
Si aucun produit ne bénéficie d’une remise, le tableau sans la colonne « Remise » est bien affiche, MAIS plusieurs fois, avec les deux lignes de produit, puis le premier produit uniquement, puis le deuxième,… et avec entre chaque tableau :

[!-- ELSE 0 --]

Il doit y avoir interférence entre les lignes du tableau et le test. Ou alors je me plante quelque part… :-\ mais où ?

Ci joint le modèle et résultats avec/sans remise…

DEVIS-TEST.zip (205 KB)

DEVIS-TEST-MODELE.odt : fichier modèle
DEVIS-TEST-1.odt: produit 1 avec remise, produit 2 sans remise
DEVIS-TEST-2.odt: produit 1 sans remise, produit 2 avec remise
DEVIS-TEST-3.odt: produit 1 et produit 2 avec remise
DEVIS-TEST-4.odt: produit 1 et produit 2 sans remise

Et encore un grand merci…

Bonjour,
le problème est que, dans un doc .odt vous avez deux lignes BeginRows! Et les développeurs ne ont pas encore résoudre cette question. Son problème connu mais pas de retour à résoudre bientôt.

1 « J'aime »

Moi pas. J’ai beau copier/coller par exemple {line_up_locale} à partir d’un texte brut, ça ne marche toujours pas. Pas plus qu’un « Effacer le formatage direct ».

Je crois que je vais apprendre à me dispenser de cette « fonctionnalité »… :o/

Ce serait dommage de vous priver de cette fonctionnalité je trouve. Essayez avec ce fichier qui fonctionne chez moi :

ITSL-DEVIS-P-02-TEST.odt (50.5 KB)

Comme cela on verra si ça vient de votre fichier ou non…

Bonjour, merci pour l’information, je vais donc me contenter de cacher le titre de la colonne en attendant mieux, même si c’est beaucoup moins « sexy »…

Merci, je viens d’essayer votre fichier : ça ne fonctionne pas. J’ai exactement le même résultat qu’avec mon modèle comme je le décris sur le bug.

J’y reviendrai peut-être plus tard, j’ai d’autres engagements à honorer avant d’éplucher ces trucs chronophages. ;o)

Donc ce ne serait pas dans votre fichier mais bien dans votre installation. Pour être sûr, vérifiez que vous êtes bien en 3.6.3.
Encore merci et bon travail !