scripts/lib/impression/__init__.py
J.Benoist Leger 4bd2ff1276 Log de l'imprimante pour restimation des coutes
darcs-hash:20080625180137-fbba6-dc95182c2ee486d6535d46ad8733e72bc235e8c1.gz
2008-06-25 20:01:37 +02:00

523 lines
20 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# #############################################################
# ..
# .... ............ ........
# . ....... . .... ..
# . ... .. .. .. .. ..... . ..
# .. .. ....@@@. .. . ........ .
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
# ...@@@.... @@@ .@@.......... ........ ..... ..
# . ..@@@@.. . .@@@@. .. ....... . .............
# . .. .... .. .. . ... ....
# . . .... ............. .. ...
# .. .. ... ........ ... ...
# ................................
#
# #############################################################
# __init__.py
#
# Classe impression
#
# Copyright (c) 2006 by www.crans.org
# #############################################################
"""
Classe pour gŽrer l'envoie de pdf ˆ l'imprimante.
Calcule le cožt des options d'impression.
"""
__version__ = '1'
import sys, syslog, os.path
sys.path.append('/usr/scripts/gestion')
import config
import cout
from crans.utils import QuoteForPOSIX as escapeForShell
import crans.utils.logs
log = crans.utils.logs.getFileLogger('impression')
# Début : Ajout log pour réestimer les coûts
import time
import hptools
comm = hptools.snmp(host="laserjet.adm.crans.org",version="1",community="public")
# Fin
# ######################################################## #
# CONSTANTES #
# ######################################################## #
#
#
# Début : Ajout log pour réestimer les coûts
FICHIER_LOG="/var/log/log_couts/impressions"
SNMP_CAR_B_PC="enterprises.11.2.3.9.4.2.1.4.1.10.1.1.18.1.0"
SNMP_CAR_C_PC="enterprises.11.2.3.9.4.2.1.4.1.10.1.1.18.2.0"
SNMP_CAR_M_PC="enterprises.11.2.3.9.4.2.1.4.1.10.1.1.18.3.0"
SNMP_CAR_Y_PC="enterprises.11.2.3.9.4.2.1.4.1.10.1.1.18.4.0"
SNMP_CAR_B_PR="enterprises.11.2.3.9.4.2.1.4.1.10.5.1.1.1.0"
SNMP_CAR_C_PR="enterprises.11.2.3.9.4.2.1.4.1.10.5.1.1.2.0"
SNMP_CAR_M_PR="enterprises.11.2.3.9.4.2.1.4.1.10.5.1.1.3.0"
SNMP_CAR_Y_PR="enterprises.11.2.3.9.4.2.1.4.1.10.5.1.1.4.0"
SNMP_TAM_B_PC="enterprises.11.2.3.9.4.2.1.4.1.10.1.1.37.5.0"
SNMP_TAM_C_PC="enterprises.11.2.3.9.4.2.1.4.1.10.1.1.37.6.0"
SNMP_TAM_M_PC="enterprises.11.2.3.9.4.2.1.4.1.10.1.1.37.7.0"
SNMP_TAM_Y_PC="enterprises.11.2.3.9.4.2.1.4.1.10.1.1.37.8.0"
SNMP_TAM_B_PR="enterprises.11.2.3.9.4.2.1.4.1.10.5.1.1.5.0"
SNMP_TAM_C_PR="enterprises.11.2.3.9.4.2.1.4.1.10.5.1.1.6.0"
SNMP_TAM_M_PR="enterprises.11.2.3.9.4.2.1.4.1.10.5.1.1.7.0"
SNMP_TAM_Y_PR="enterprises.11.2.3.9.4.2.1.4.1.10.5.1.1.8.0"
# Fin
DECOUVERT_AUTHORISE = config.impression.decouvert
PAS_D_AGRAPHES = "pasdagraphes"
AGRAPHE_DIAGONALE = "agraphediagonale"
UNE_AGRAPHE = "uneagraphe"
DEUX_AGRAPHE = "Deuxagraphes"
TROIS_AGRAPHE = "troisAgraphes"
STITCHING = "stitching"
AGRAPHES_VALEURS_POSSIBLES = [PAS_D_AGRAPHES, AGRAPHE_DIAGONALE, UNE_AGRAPHE, DEUX_AGRAPHE, TROIS_AGRAPHE, STITCHING]
NB_AGRAPHES = {
PAS_D_AGRAPHES: 0,
AGRAPHE_DIAGONALE: 1,
UNE_AGRAPHE: 1,
DEUX_AGRAPHE: 2,
TROIS_AGRAPHE: 3,
STITCHING: 6,
}
PAPIER_A4 = "A4"
PAPIER_A4_TRANSPARENT = "A4tr"
PAPIER_A3 = "A3"
PAPIER_VALEURS_POSSIBLES = [PAPIER_A4, PAPIER_A4_TRANSPARENT, PAPIER_A3]
IMPRESSION_COULEUR = "couleurs"
IMPRESSION_NB = "nb"
COULEURS_VALEURS_POSSIBLES = [IMPRESSION_COULEUR, IMPRESSION_NB]
IMPRESSION_RECTO = "recto"
IMPRESSION_RECTO_VERSO = "rectoverso"
IMPRESSION_RECTO_VERSO_SHORT = "rectoversoshort"
DISPOSITION_VALEURS_POSSIBLES = [IMPRESSION_RECTO, IMPRESSION_RECTO_VERSO, IMPRESSION_RECTO_VERSO_SHORT]
PU_AGRAPHE = config.impression.c_agrafe / 100.
PU_FEUILLE = {
PAPIER_A4: config.impression.c_a4/100,
PAPIER_A4_TRANSPARENT: config.impression.c_trans/100,
PAPIER_A3: config.impression.c_a3/1000,
}
LABELS = {
PAS_D_AGRAPHES: "pas d'agrafe",
AGRAPHE_DIAGONALE: 'une agrafe en diagonale',
UNE_AGRAPHE: 'une agrafe en haut',
DEUX_AGRAPHE: '2 agrafes',
TROIS_AGRAPHE: '3 agrafes',
STITCHING: 'stitching (6 agrafes)',
PAPIER_A4: "A4",
PAPIER_A4_TRANSPARENT: "A4 transparent",
PAPIER_A3: "A3",
IMPRESSION_COULEUR: "impression couleurs",
IMPRESSION_NB: "impression noir et blanc",
IMPRESSION_RECTO: "impression recto",
IMPRESSION_RECTO_VERSO: "impression recto-verso",
IMPRESSION_RECTO_VERSO_SHORT: "impression recto-verso",
}
LPR_OPTIONS = {
PAS_D_AGRAPHES: ' -o StapleLocation=None',
AGRAPHE_DIAGONALE: ' -o StapleLocation=1diagonal',
UNE_AGRAPHE: ' -o StapleLocation=1parallel',
DEUX_AGRAPHE: ' -o StapleLocation=2parallel',
TROIS_AGRAPHE: ' -o StapleLocation=3parallel',
STITCHING: ' -o StapleLocation=Stitching',
PAPIER_A4: ' -o InputSlot=Tray4 -o pdf-paper=571x817 -o PageSize=A4',
PAPIER_A4_TRANSPARENT: ' -o PageSize=A4 -o InputSlot=Tray1 -o Media=Transparency',
PAPIER_A3: ' -o pdf-expand -o pdf-paper=825x1166 -o InputSlot=Tray3 -o HPPaperPolicy=A3 -o PageSize=A3',
IMPRESSION_COULEUR: ' -o HPColorasGray=False',
IMPRESSION_NB: ' -o HPColorasGray=True',
IMPRESSION_RECTO: ' -o sides=one-sided',
IMPRESSION_RECTO_VERSO: ' -o sides=two-sided-long-edge',
IMPRESSION_RECTO_VERSO_SHORT: ' -o sides=two-sided-short-edge',
}
# ######################################################## #
# ERREURS #
# ######################################################## #
#
class FichierInvalide(Exception):
"""
Exception renvoyée lorsqu'un fichier ne passe pas.
utilisée avec deux arguments : une chaîndéÃécrivant l'erreur et une chÃine avec le nom du fichier
"""
def __str__(self):
"""
Description de l'erreur.
"""
return self.args[0]
def file(self):
"""
Nom du fichier qui pose problème
"""
try:
return self.args[1]
except:
return "n/a"
class SoldeInsuffisant(Exception):
"""
Solde insuffisant pour l'impression demandée
"""
pass
class PrintError(Exception):
"""
Erreur lors de l'impression
"""
pass
class SettingsError(Exception):
"""
Erreur de paramètres.
"""
pass
# ######################################################## #
# CLASSE IMPRESSION #
# ######################################################## #
#
#
class impression:
"""impression
Un objet impression correspond ˆ un fichier pdf et un adhŽrent.
"""
# fichier (chemin)
_fichier = ""
# adherent (instance)
_adh = None
# paramettres
_settings = {
'agraphes': PAS_D_AGRAPHES,
'papier': PAPIER_A4,
'couleurs': IMPRESSION_COULEUR,
'recto_verso': IMPRESSION_RECTO_VERSO,
'copies':1,
}
# le prix de l'impression
_prix = 0.0
_nb_pages = 0
_details_devis = []
# le cout de base encre pour une impression en couleurs/n&b
# (prix pour papier A4)
_base_prix_nb = 0.0
_base_prix_couleurs = 0.0
def __init__(self, path_to_pdf, adh = None):
"""impression(path_to_pdf [, adh])
CrŽe un nouvel objet impression ˆ partir du fichier pdf pointŽ par path_to_pdf.
Si adh ext donnŽ, il peut <20>tre soit une instance d'un objet adhŽrent de crans_ldap soit le login de l'adhŽrent.
L<>ve l'exception FichierInvalide si le fichier n'existe pas ou si ce n'est pas un pdf.
"""
self._fichier = path_to_pdf
# on verifie que le fichier existe
if not os.path.isfile(path_to_pdf):
raise FichierInvalide, ("Fichier introuvable", path_to_pdf)
if not open(path_to_pdf).read().startswith("%PDF"):
raise FichierInvalide, ("Le fichier ne semble pas etre un PDF", path_to_pdf)
self._adh = adh
# calcule le prix de l'encre tout de suite
try:
self._base_prix_couleurs, self._nb_pages = cout.base_prix_couleurs(path_to_pdf)
self._base_prix_nb, self._nb_pages = cout.base_prix_nb(path_to_pdf)
except ValueError, e:
raise FichierInvalide, ("PDF bugge, Analyse impossible : %s." % e, path_to_pdf)
except Exception, e:
raise Exception, "Erreur dans le calcul du cout : %s " % str(e)
self._calcule_prix()
def changeSettings(self, agraphes = None, papier = None, couleurs = None, recto_verso=None, copies=None):
"""changeSettings([keyword=value])
Change les parametres de l'impression, recalcule et renvoie le nouveau prix.
L<>ve une exceotion SettingError si les param<61>tres son invalides.
"""
#recalcule et renvoie le prix
if (couleurs):
if couleurs not in COULEURS_VALEURS_POSSIBLES:
raise SettingsError, "Valeur de couleurs inconnue : %s" % str(couleurs)
self._settings['couleurs'] = couleurs
if (papier):
if papier not in PAPIER_VALEURS_POSSIBLES:
raise SettingsError, "Valeur de papier inconnue : %s" % str(papier)
self._settings['papier'] = papier
if (copies):
try:
int(copies)
if int(copies) <1:
raise Exception
except:
raise SettingsError, "Valeur incorecte pour le nombre de copies"
self._settings['copies'] = copies
if (recto_verso):
if recto_verso not in DISPOSITION_VALEURS_POSSIBLES:
raise SettingsError, "Valeur inconnue : %s" % str(recto_verso)
if papier==PAPIER_A4_TRANSPARENT and (recto_verso==IMPRESSION_RECTO_VERSO or recto_verso==IMPRESSION_RECTO_VERSO_SHORT):
raise SettingsError, "Pas de recto-verso sur du papier transparent !!"
self._settings['recto_verso'] = recto_verso
if (agraphes):
if agraphes not in AGRAPHES_VALEURS_POSSIBLES:
raise SettingsError, "Valeur inconnue pour agrafes : %s" % str(agrafes)
if papier!=PAPIER_A4 and agraphes!=PAS_D_AGRAPHES:
raise SettingsError, "Le type de papier choisi ne permet pas d'utiliser l'agrafeuse"
if recto_verso==IMPRESSION_RECTO_VERSO or recto_verso==IMPRESSION_RECTO_VERSO_SHORT:
if self._nb_pages > 100 and agraphes!=PAS_D_AGRAPHES:
raise SettingsError, "Le document est trop volumineux pour utiliser l'agrafeuse"
else:
if self._nb_pages > 50 and agraphes!=PAS_D_AGRAPHES:
raise SettingsError, "Le document est trop volumineux pour utiliser l'agrafeuse"
self._settings['agraphes'] = agraphes
return self._calcule_prix()
def printSettings(self):
"""printSettings()
Affiche les param<61>tres courrants sur la sortie standard
"""
print "Type impression: " + LABELS[self._settings['couleurs']]
print "Agraphes: " + LABELS[self._settings['agraphes']]
print "Papier: " + LABELS[self._settings['papier']]
print "Disposition: " + LABELS[self._settings['recto_verso']]
print "Copies: " + str(self._settings['copies'])
def prix(self):
"""prix()
Renvoie le prix courrant de l'impression
"""
return self._prix
def fileName(self):
"""fileName()
renvoie le nom du fichier pdf (exemple : monPdf.pdf)
"""
return os.path.basename(self._fichier)
def filePath(self):
"""filePath()
renvoie le chemin d'acc<EFBFBD>s au fichier pdf.
"""
return self._fichier
def devisDetaille(self):
"""devisDetaille()
renvoie un disctionnaire contenant le devis (intitulŽ, PU., quantitŽ) pour tous les ŽlŽments de l'impression
(papier, encre, agrafes...)
"""
return self._details_devis
def pages(self):
"""pages()
renvoie le nombre de pages du document (page au sens nombre de faces ˆ imprimer et non le nombre de feuilles)
"""
return self._nb_pages
def imprime(self):
"""imprime()
imprime le document pdf. dŽbite l'adhŽrent si adhŽrent il y a.
(si il a ŽtŽ indiquŽ ˆ l'initialisation de l'objet)
"""
# debite l'adhŽrent si adherent il y a
if (self._adh != None):
adh = self._get_adh(self._adh)
if (self._prix > (adh.solde() - DECOUVERT_AUTHORISE)):
raise SoldeInsuffisant
adh.solde(-self._prix, "impression: " + self._fichier)
adh.save()
del adh
# imprime le document
self._exec_imprime()
def printDevis(self):
"""printDevis()
Affiche le devis sur la sortie standard.
"""
print "titre \t\t | p.u. \t quandtite \t total"
for anItem in self._details_devis:
print anItem[0][:5] + "\t\t | " + str(anItem[1]) + "\t\t | " + str(anItem[2]) + "\t\t | " + str(anItem[1]*anItem[2])
def _calcule_prix(self):
prix = 0
facture = []
# clacul du prix total pour l'encre
if (self._settings['couleurs'] == IMPRESSION_COULEUR):
base_prix_encre = self._base_prix_couleurs
else:
base_prix_encre = self._base_prix_nb
if (self._settings['papier'] == PAPIER_A3):
pu_encre = base_prix_encre * 2
else:
pu_encre = base_prix_encre
facture.append((
LABELS[self._settings['couleurs']] + ' sur papier ' + LABELS[self._settings['papier']],
pu_encre, self._settings['copies']))
prix+= self._settings['copies'] * pu_encre
#calcul du prix des feuilles
if (self._settings['recto_verso'] == IMPRESSION_RECTO_VERSO) or (self._settings['recto_verso'] == IMPRESSION_RECTO_VERSO_SHORT):
nbfeuilles = int(self._nb_pages/2.+0.5) * self._settings['copies']
else:
nbfeuilles = self._nb_pages * self._settings['copies']
facture.append((
'feuilles ' + LABELS[self._settings['papier']],
PU_FEUILLE[self._settings['papier']],
nbfeuilles))
prix+= PU_FEUILLE[self._settings['papier']] * nbfeuilles
# calcul prix des Agraphes
facture.append((
'agrafes',
PU_AGRAPHE,
NB_AGRAPHES[self._settings['agraphes']] * self._settings['copies']))
prix+= NB_AGRAPHES[self._settings['agraphes']] * self._settings['copies'] * PU_AGRAPHE
# arrondit
prix = int((prix*100) + 0.5)/100.
self._prix = prix
self._details_devis = facture
return prix
def _get_adh(self, adh):
if type(adh) == str:
import sys
sys.path.append("/usr/scripts/gestion/")
#from ldap_crans_test import crans_ldap
from ldap_crans import CransLdap
adh = CransLdap().getProprio(adh, 'w')
return adh
## ################################# ##
## fonction qui imprime pour de vrai ##
## ################################# ##
##
def _exec_imprime(self):
""" Envoie l'impression a l'imprimante avec les parametres actuels """
if (self._adh != None):
log.info('Impression [%s] : %s' % (self._adh, self._fichier))
else:
log.info("Impression : %s" % self._fichier)
# Envoi du fichier a CUPS
options =''
# Creation de la liste d'options
# pour le nombre de copies et specifie non assemblee
#options += '-# %d -o Collate=True' % self.nb_copies
# Pour specifier l'imprimante
options += ' -P laserjet'
#Indique la presence d'un bac de sortie avec agrafeuse
options += " -o Option20=MBMStaplerStacker -o OutputBin=StackerStapled"
# Pour specifier la version du language postscript utilise par pdftops
options += ' -o pdf-level3'
# Pour donner le titre de l'impression
options += " -T '%s'" % self._fichier
# Pour donner le login de l'adherent
if (self._adh != None):
options += ' -U %s' % self._adh
# Pour demander une page de garde
#options += ' -o job-sheets=crans' #page de garde de type standard
#options += " -o job-billing=%.2f" % self.cout
#options += ' -o job-sheets=none'
# option agrafes
options += LPR_OPTIONS[self._settings['agraphes']]
# option papier
options += LPR_OPTIONS[self._settings['papier']]
# option disposition
options += LPR_OPTIONS[self._settings['recto_verso']]
# options couleurs
options += LPR_OPTIONS[self._settings['couleurs']]
# Début : Ajout log pour réestimer les coûts
# Commandes snmp recuperation des etats
val_car_b_pc=int(comm.get(SNMP_CAR_B_PC))
val_car_c_pc=int(comm.get(SNMP_CAR_C_PC))
val_car_m_pc=int(comm.get(SNMP_CAR_M_PC))
val_car_y_pc=int(comm.get(SNMP_CAR_Y_PC))
val_car_b_pr=int(comm.get(SNMP_CAR_B_PR))
val_car_c_pr=int(comm.get(SNMP_CAR_C_PR))
val_car_m_pr=int(comm.get(SNMP_CAR_M_PR))
val_car_y_pr=int(comm.get(SNMP_CAR_Y_PR))
val_tam_b_pc=int(comm.get(SNMP_TAM_B_PC))
val_tam_c_pc=int(comm.get(SNMP_TAM_C_PC))
val_tam_m_pc=int(comm.get(SNMP_TAM_M_PC))
val_tam_y_pc=int(comm.get(SNMP_TAM_Y_PC))
val_tam_b_pr=int(comm.get(SNMP_TAM_B_PR))
val_tam_c_pr=int(comm.get(SNMP_TAM_C_PR))
val_tam_m_pr=int(comm.get(SNMP_TAM_M_PR))
val_tam_y_pr=int(comm.get(SNMP_TAM_Y_PR))
fichier_log_imp=open(FICHIER_LOG,"a")
fichier_log_imp.write("%d %3d %2s : %3d %3d %3d %3d : %5d %5d %5d %5d : %3d %3d %3d %3d : %5d %5d %5d %5d : %s\n" %
(time.time(),self._settings['copies'],self._settings['papier'],
val_car_b_pc,
val_car_c_pc,
val_car_m_pc,
val_car_y_pc,
val_car_b_pr,
val_car_c_pr,
val_car_m_pr,
val_car_y_pr,
val_tam_b_pc,
val_tam_c_pc,
val_tam_m_pc,
val_tam_y_pc,
val_tam_b_pr,
val_tam_c_pr,
val_tam_m_pr,
val_tam_y_pr,
self._fichier) )
fichier_log_imp.close()
# Fin
liste_nom_fichier_pdf=(' '+escapeForShell( self._fichier ) )*self._settings['copies']
import commands
#(status,rep) = commands.getstatusoutput("lpr %s %s" % (options, self.nom_fichier_pdf))
(status,rep) = commands.getstatusoutput("lpr %s %s" % (options, liste_nom_fichier_pdf))
if status != 0:
log.error("erreur impression")
log.error("lpr status:%d | rep: %s" % (status, rep))
raise PrintError, "lpr %s %s \n status:%d rep: %s" % (options, liste_nom_fichier_pdf, status, rep)