#!/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, time sys.path.append('/usr/scripts/gestion') from config import impression from hptools import snmp from crans.utils import QuoteForPOSIX as escapeForShell import crans.utils.logs # ######################################################## # # CONSTANTES # # ######################################################## # LOG = crans.utils.logs.getFileLogger('impression') COMM = hptools.snmp(host="imprimante.adm.crans.org",version="1",community="public") FICHIER_LOG="/var/log/log_couts/impressions" SNMP_CAPA_B = "mib-2.43.11.1.1.8.1.1" SNMP_CAPA_C = "mib-2.43.11.1.1.8.1.2" SNMP_CAPA_M = "mib-2.43.11.1.1.8.1.3" SNMP_CAPA_Y = "mib-2.43.11.1.1.8.1.4" SNMP_TON_B = "mib-2.43.11.1.1.9.1.1" SNMP_TON_C = "mib-2.43.11.1.1.9.1.2" SNMP_TON_M = "mib-2.43.11.1.1.9.1.3" SNMP_TON_Y = "mib-2.43.11.1.1.9.1.4" SNMP_BAC1 = "mib-2.43.8.2.1.10.1.2" SNMP_BAC2 = "mib-2.43.8.2.1.10.1.3" SNMP_BAC3 = "mib-2.43.8.2.1.10.1.4" SNMP_BAC4 = "mib-2.43.8.2.1.10.1.5" SNMP_ETAT = "hrPrinterStatus.1" SNMP_ERR = "hrPrinterDetectedErrorState.1" DECOUVERT_AUTHORISE = config.impression.decouvert # ######################################################## # # ERREURS # # ######################################################## # # class FichierInvalide(Exception): """ Exception renvoyée lorsqu'un fichier ne passe pas. utilisée avec deux arguments : une chaîne décrivant l'erreur et une chaîne 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 = { 'agrafage': 'None', 'papier': 'A4' 'couleur': False, 'recto_verso': False, 'livret': False, 'copies': 1, 'portrait': True, } # le prix de l'impression _prix = 0.0 _nb_pages = 0 # 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 ê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 self._adh = adh # 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) # on compte les pages self._pages = int(os.popen("pdfinfo %s | grep Pages " % (self._fichier)).readline().split()[1]) # calcule le prix de l'encre tout de suite self._calcule_prix() def _pdfbook(self): if self.taille == 'A3': pdfbook = "pdfbook --paper a3paper %s" else: pdfbook = "pdfbook %s" (status, rep) = commands.getstatusoutput(pdfbook % self._fichier) self._fichier = "%s-book.pdf" % self.n_fichier[:-4] if status != 0: log.error("pdfbook status:%d | rep: %s" % (status, rep)) raise FichierInvalide, ("pdfbook: Impossible de convertir le fichier", self._fichier) def changeSettings(self, **kw): """changeSettings([keyword=value]) Change les parametres de l'impression, recalcule et renvoie le nouveau prix. Lève une exceotion SettingError si les paramètres son invalides. """ #recalcule et renvoie le prix couleur = kw.get('couleur', None) if couleur in [True, False]: self._settings['couleur'] = couleur try: if int(kw['copies']) >= 1: self._settings['copies'] = int(kw['copies']) except: pass recto_verso = kw.get('recto_verso', None) if recto_verso in [True, False]: self._settings['recto_verso'] = recto_verso papier = kw.get('papier', None) if papier in ['A4', 'A3', 'A4tr']: self._settings['papier'] = papier if papier == 'A4tr': self._settings['recto_verso'] = False self._settings['agrafage'] = 'None' agrafage = kw.get('agrafage', None) if agrafage in ["None", "TopLeft", "Top", "TopRight", "Left", "Right", "BottomLeft", "BottomRight"]: self._settings['agrafage'] = agrafage livret = kw.get('livret', None) if livret in [True, False]: self._settings['livret'] = livret self._settings['portrait'] = not(livret) if livret: self._settings['recto_verso'] = True self._settings['agrafage'] = 'None' if self._settings['papier'] == 'A4tr': self._settings['papier'] = 'A4' return self._calcule_prix() def printSettings(self): """printSettings() Affiche les paramètres courrants sur la sortie standard """ dict_agrafage = { "None" : "aucune agrafe", "TopLeft" : u"agrafe en haut à gauche", "TopRight" : u"agrafe en haut à droite", "BottomLeft" : u"agrafe en bas à gauche", "BottomRight" : u"agrafe en bas à droite", "Left": u"deux agrafes sur le bord gauche", "Right" : u"deux agrafes sur le bord droit", "Top" : u"deux agrafes sur le bord supérieur", "Bottom" : u"deux agrafes sur le bord inférieur" } dict_papier = { 'A4' : "Papier A4 ordinaire", 'A3' : "Papier A3 ordinaire", 'A4tr' : "Transparent A4" } if self._settings['couleur']: print "Type impression: Couleur" else: print "Type impression: Noir et blanc" print "Papier: " + dict_papier[self._settings['papier']] if self._settings['livret']: print u"Agrafage: Livret (piqûre à cheval)" else: print "Agrafage: " + dict_agrafage[self._settings['agrafage']] if self._setting['recto_verso']: print "Disposition: recto/verso" else: print "Disposition: recto" 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ès au fichier pdf. """ return self._fichier 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 _calcule_prix(self): faces = self._pages if self._settings['livret']: feuilles = int(faces+3/4) elif self._settings['recto_verso']: feuilles = int(faces/2.+0.5) else: feuilles = faces if (self._settings['papier'] == "A3"): c_papier = impression.c_a3 pages = 2*faces else: pages = faces if self._settings['papier'] == "A4tr": c_papier = impression.c_trans else: c_papier = impression.c_a4 if self._settings['couleur']: c_impression = c_papier * pages + impression.c_face_couleur * pages else: c_impression = c_papier * pages + impression.c_face_nb * pages # Cout des agrafes if self._settings['agrafe'] in ["Top", "Bottom", "Left", "Right"] or self._settings['livret']: nb_agrafes = 2 elif self._settings['agrafe'] in ["None", None]: nb_agrafes = 0 else: nb_agrafes = 1 if feuilles <= 50: c_agrafes = nb_agrafes * impression.c_agrafe else: c_agrafes = 0 c_total = int(self._settings['copies'] * ( c_impression + impression.fact + c_agrafes ) + 0.5) # arrondi et facture return float(c_total)/100 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._settings['livret']: self._pdfbook() if (self._adh != None): log.info('Impression [%s] : %s' % (self._adh, self._fichier)) else: log.info("Impression : %s" % self._fichier) # Envoi du fichier à CUPS options = '' # Création de la liste d'options # pour le nombre de copies et specifie non assemblee #options += '-# %d -o Collate=True' % self.nb_copies # Pour spécifier l'imprimante options += ' -P canon_irc3580' # Pour spécifier la version du language postscript utilisé par pdftops # options += ' -o pdf-level3' # Pour donner le titre de l'impression options += " -T \"%s\"" % self.nom_job.replace("\"","\\\"") # Pour donner le login de l'adherent options += ' -U \"%s\"' % self.user.replace("\"","\\\"") # 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' #Indique la présence d'un bac de sortie avec agrafeuse # options += " -o Option20=MBMStaplerStacker -o OutputBin=StackerDown" if self._settings['paper'] == 'A4tr': options += ' -o InputSlot=SideDeck -o MediaType=OHP' options += ' -o pdf-paper=571x817 -o PageSize=A4' elif self._settings['paper'] == 'A4': options += ' -o pdf-paper=571x817 -o PageSize=A4' else: options += ' -o pdf-expand -o pdf-paper=825x1166 -o PageSize=A3' if self._settings['portrait']: if self._settings['recto_verso']: options += ' -o sides=two-sided-long-edge' else: options += ' -o sides=one-sided' else: if self._settings['recto_verso']: options += ' -o sides=two-sided-short-edge' else: options += ' -o sides=one-sided' if self._settings['couleur']: options += ' -o CNColorMode=color' else: options += ' -o CNColorMode=mono' if self._settings['livret']: options += ' -o CNSaddleStitch=True' options += ' -o OutputBin=TrayC' else: options += ' -o OutputBin=TrayA' options += ' -o StapleLocation=%s' % self._settings['agrafage'] cmd = "lpr %s -# %d %s" % (options, self._settings['copies'], self._fichier) (status, rep) = commands.getstatusoutput(cmd) if status != 0: log.error("erreur impression") log.error("lpr status:%d | rep: %s" % (status, rep)) raise PrintError, "%s \n status:%d rep: %s" % (cmp, status, rep)