# Copyright (C) 2015 Chintalagiri Shashank
#
# This file is part of Tendril.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This file is part of tendril
See the COPYING, README, and INSTALL files for more information
"""
import atexit
import cPickle
import os
import qrcode
import render
from tendril.utils import log
from tendril.utils.config import COMPANY_LOGO_PATH
from tendril.utils.config import COMPANY_NAME
from tendril.utils.config import INSTANCE_CACHE
from tendril.utils.fsutils import TEMPDIR
from tendril.utils.files.pdf import merge_pdf
logger = log.get_logger(__name__, log.INFO)
LABEL_TEMPLATES_ROOT = 'labels'
[docs]class LabelBase(object):
templatefile = None
def __init__(self, code, ident, sno, branding=None, logo=None,
include_qr=True, include_logo=True):
self._code = code
self._sno = sno
self._ident = ident
if branding is None:
self._branding = COMPANY_NAME
else:
self._branding = branding
if logo is None and include_logo is True:
self._logo = COMPANY_LOGO_PATH
else:
self._logo = logo
self._include_qr = include_qr
self._include_logo = include_logo
self._qr_path = None
if self._include_qr is True:
self._gen_qrcode()
@property
def code(self):
return self._code
@property
def sno(self):
return self._sno
@property
def ident(self):
# if len(self._ident) > 16:
# return r"\tiny " + self._ident
# if len(self._ident) > 14:
# return r"\scriptsize " + self._ident
# else:
return r"\footnotesize " + self._ident
@property
def branding(self):
return self._branding
@property
def include_logo(self):
return self._include_logo
@property
def include_qr(self):
return self._include_qr
@property
def logo(self):
return self._logo
@property
def qrcode(self):
return self._qr_path
[docs] def _gen_qrcode(self, wfpath=None):
if wfpath is None:
wfpath = os.path.join(TEMPDIR, 'qrcache')
if not os.path.exists(wfpath):
os.makedirs(wfpath)
qr = qrcode.make(self._ident + ' ' + self._sno)
self._qr_path = os.path.join(
wfpath, 'QR-' + self._ident + '-' + self._sno + '.png'
)
qr.save(self._qr_path)
def __repr__(self):
return "<Label for " + self._ident + ' ' + self._sno + '>'
[docs]class LabelCW1(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'CW1_template.tex')
lpp = 88
[docs]class LabelCW3(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'CW3_template.tex')
lpp = 288
[docs]class LabelP1(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'CW1_template.tex')
lpp = 88
[docs]class LabelP2(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'P2_template.tex')
lpp = 120
[docs]class LabelD1(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'CW1_template.tex')
lpp = 88
[docs]class LabelCable1(LabelCW3):
def __init__(self, code, ident, sno, **kwargs):
super(LabelCable1, self).__init__(code, ident, sno)
self._desc = kwargs['desc']
@property
def desc(self):
return self._desc
@property
def ident(self):
return self._ident
[docs]class LabelBox1(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'BOX1_template.tex')
lpp = 51
def __init__(self, code, ident, sno, **kwargs):
super(LabelBox1, self).__init__(code, ident, sno)
self._desc = kwargs['desc']
@property
def desc(self):
return self._desc
@property
def ident(self):
return self._ident
[docs]class LabelPack1(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'PACK1_template.tex')
lpp = 20
def __init__(self, code, ident, sno, **kwargs):
super(LabelPack1, self).__init__(code, ident, sno)
self._desc = kwargs['desc']
@property
def desc(self):
return self._desc
@property
def ident(self):
return self._ident
[docs]class LabelBox2(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'BOX2_template.tex')
lpp = 51
def __init__(self, code, ident, sno, **kwargs):
super(LabelBox2, self).__init__(code, ident, sno)
self._mac = kwargs['mac']
self._desc = kwargs['desc']
@property
def desc(self):
return self._desc
@property
def mac(self):
return self._mac
@property
def ident(self):
return self._ident
[docs]class LabelPack2(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'PACK2_template.tex')
lpp = 45
def __init__(self, code, ident, sno, **kwargs):
super(LabelPack2, self).__init__(code, ident, sno)
self._mac = kwargs['mac']
self._desc = kwargs['desc']
@property
def desc(self):
return self._desc
@property
def mac(self):
return self._mac
@property
def ident(self):
return self._ident
[docs]class LabelIDT(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'IDT_template.tex')
lpp = 88
def __init__(self, code, ident, sno, **kwargs):
super(LabelIDT, self).__init__(code, ident, sno,
include_logo=False, include_qr=False)
self._qty = kwargs['qty']
@property
def qty(self):
return self._qty
@property
def ident(self):
return self._ident
[docs]class LabelSM1(LabelBase):
templatefile = os.path.join(LABEL_TEMPLATES_ROOT, 'SM1_template.tex')
lpp = 490
def __init__(self, code, ident, sno, **kwargs):
super(LabelSM1, self).__init__(code, ident, sno,
include_logo=False, include_qr=False)
@property
def ident(self):
return self._ident
[docs]def get_labelbase(code):
# TODO change this dispatch to use introspection instead
if code == 'CW1':
return LabelCW1
elif code == 'CW3':
return LabelCW3
elif code == 'D1':
return LabelD1
elif code == 'P1':
return LabelP1
elif code == 'P2':
return LabelP2
elif code == 'IDT':
return LabelIDT
elif code == 'LBOX1':
return LabelBox1
elif code == 'LPACK1':
return LabelPack1
elif code == 'LBOX2':
return LabelBox2
elif code == 'LPACK2':
return LabelPack2
elif code == 'LCABLE1':
return LabelCable1
elif code == 'LSM1':
return LabelSM1
else:
return LabelBase
[docs]class LabelSheet(object):
def __init__(self, base, code):
self._base = base
self._code = code
self._labels = []
@property
def code(self):
return self._code
@property
def base(self):
return self._base
@property
def labels(self):
for label in self._labels:
yield label
[docs] def add_label(self, label):
self._labels.append(label)
@property
def nl(self):
return len(self._labels)
[docs] def generate_pdf(self, targetfolder, force=True):
labels = [label for label in self._labels]
nl = len(labels)
sheets, remain = divmod(nl, self.base.lpp)
if nl == 0:
return None
if remain > self.base.lpp * 0.8 or force is True:
stage = {'labels': labels}
self._labels = []
logger.info("Creating all labels for sheet : " + self._code)
elif sheets > 0:
stage = {'labels': labels[:self.base.lpp * sheets]}
self._labels = labels[self.base.lpp * sheets:]
logger.info("Holding back " +
str(remain) + " labels for sheet : " + self._code)
else:
logger.info("Not generating labels for sheet : " + self._code +
' ' + str(remain))
return None
return render.render_pdf(
stage,
self._base.templatefile,
os.path.join(targetfolder, 'labels-' + self.code + '.pdf')
)
[docs] def clear_sno_label(self, sno):
if self._labels is None:
self._labels = []
for label in self._labels:
if label.sno == sno:
self._labels.remove(label)
[docs]class LabelMaker(object):
def __init__(self):
self._sheets = []
[docs] def add_label(self, code, ident, sno, **kwargs):
# self._clear_sno_label(sno)
sheet = self._get_sheet(code)
label = sheet.base(code, ident, sno, **kwargs)
sheet.add_label(label)
[docs] def _get_sheet(self, code):
if code not in self._sheetdict.keys():
self._sheets.append(LabelSheet(get_labelbase(code), code))
return self._sheetdict[code]
@property
def _sheetdict(self):
return {x.code: x for x in self._sheets}
[docs] def generate_pdfs(self, targetfolder, force=False):
rval = []
for sheet in self._sheets:
opath = sheet.generate_pdf(targetfolder, force)
if opath is not None:
rval.append(opath)
return rval
[docs] def generate_pdf(self, targetfolder, force=False):
files = self.generate_pdfs(targetfolder, force=force)
if len(files) == 0:
return None
elif len(files) == 1:
return files[0]
else:
return merge_pdf(files,
os.path.join(targetfolder, 'labels.pdf'),
remove_sources=True)
@property
def nl(self):
return sum([x.nl for x in self._sheets])
[docs] def _clear_sno_label(self, sno):
for sheet in self._sheets:
sheet.clear_sno_label(sno)
[docs]def get_manager(persistent=False):
if persistent is True:
try:
with open(os.path.join(INSTANCE_CACHE, 'labelmaker.p'), 'rb') as f:
return cPickle.load(f)
except IOError:
return LabelMaker()
else:
return LabelMaker()
manager = get_manager(persistent=True)
[docs]def dump_manager():
with open(os.path.join(INSTANCE_CACHE, 'labelmaker.p'), 'wb') as f:
cPickle.dump(manager, f)
atexit.register(dump_manager)