-# -*- coding: utf-8 -*-
-#######################################################################################
-# Copyright © 2009 Benoît Pin <pin@cri.ensmp.fr> #
-# Plinn - http://plinn.org #
-# #
-# #
-# This program is free software; you can redistribute it and/or #
-# modify it under the terms of the GNU General Public License #
-# as published by the Free Software Foundation; either version 2 #
-# 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 General Public License for more details. #
-# #
-# You should have received a copy of the GNU General Public License #
-# along with this program; if not, write to the Free Software #
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #
-#######################################################################################
-"""
-Photo print tool. Used to link photo to print orders.
-
-
-
-"""
-
-from AccessControl import ClassSecurityInfo
-from AccessControl.requestmethod import postonly
-from Acquisition import aq_base, aq_inner
-from Globals import InitializeClass
-from OFS.OrderedFolder import OrderedFolder
-from Products.CMFCore.utils import UniqueObject, getToolByName
-from permissions import ManagePrintOrderTemplate
-from price import Price
-from utils import Message as _
-from Products.Plinn.utils import makeValidId
-from zope.component import getUtility
-from zope.component.interfaces import IFactory
-from DateTime import DateTime
-from Products.Plinn.utils import _sudo
-
-
-PRINTING_OPTIONS_ID = 'printingOptions'
-COPIES_COUNTERS = '_copies_counters'
-SOLD_OUT = 'SOLD_OUT'
-
-
-class PhotoPrintTool(UniqueObject, OrderedFolder) :
- """
- Provide utilities to configure possible printing works
- over photo of the portal.
- """
-
- id = 'portal_photo_print'
- meta_type = 'Photo print tool'
-
- security = ClassSecurityInfo()
-
- incomingOrderPath = 'commandes'
- no_shipping_threshold = 150
- shipping = 6.0
- shipping_vat = 0.196
- store_name = ''
- _order_counter = 0
- _transaction_id_counter = 0
-
- _properties = OrderedFolder._properties + (
- {'id' : 'incomingOrderPath', 'type' : 'string', 'mode' : 'w'},
- {'id' : 'no_shipping_threshold', 'type' : 'int', 'mode' : 'w'},
- {'id' : 'shipping', 'type' : 'float', 'mode' : 'w'},
- {'id' : 'shipping_vat', 'type' : 'float', 'mode' : 'w'},
- {'id' : 'store_name', 'type' : 'string', 'mode' : 'w'}
- )
-
-
- security.declarePublic('getPrintingOptionsFor')
- def getPrintingOptionsFor(self, ob) :
- "returns printing options for the given ob."
- optionsContainer = getattr(aq_inner(ob), PRINTING_OPTIONS_ID, None)
- if optionsContainer is None :
- return None
-
- counters = self.getCountersFor(ob)
- if counters.get(SOLD_OUT) :
- return None
-
- options = []
- for o in optionsContainer.objectValues() :
- if o.maxCopies == 0 or \
- counters.get(o.productReference, 0) < o.maxCopies :
- options.append(o)
-
- return options
-
- security.declarePublic('getPrintingOptionsContainerFor')
- def getPrintingOptionsContainerFor(self, ob):
- """getPrintingOptionsContainerFor
- """
- return getattr(ob, PRINTING_OPTIONS_ID, None)
-
- security.declarePrivate('getCountersFor')
- def getCountersFor(self, ob):
- if hasattr(ob.aq_self, COPIES_COUNTERS) :
- return getattr(ob, COPIES_COUNTERS)
- else :
- return {}
-
-
- security.declareProtected(ManagePrintOrderTemplate, 'createPrintingOptionsContainer')
- def createPrintingOptionsContainer(self, ob):
- container = PrintingOptionsContainer()
- setattr(ob, PRINTING_OPTIONS_ID, container)
- return getattr(ob, PRINTING_OPTIONS_ID)
-
- security.declareProtected(ManagePrintOrderTemplate, 'deletePrintingOptionsContainer')
- def deletePrintingOptionsContainer(self, ob):
- if not self.hasPrintingOptions(ob) :
- raise ValueError( _('No printing options found at %r') % ob.absolute_url() )
- else :
- delattr(ob, PRINTING_OPTIONS_ID)
-
- security.declareProtected(ManagePrintOrderTemplate, 'hasPrintingOptions')
- def hasPrintingOptions(self, ob):
- """ return boolean that instruct if there's printing
- options especially defined on ob
- """
- return hasattr(aq_base(ob), PRINTING_OPTIONS_ID)
-
-
- security.declareProtected(ManagePrintOrderTemplate, 'getPrintingOptionsSrc')
- def getPrintingOptionsSrc(self, ob) :
- optionsContainer = getattr(ob, PRINTING_OPTIONS_ID, None)
- if optionsContainer is None :
- return None
- src = optionsContainer.aq_inner.aq_parent
- return src
-
- security.declareProtected(ManagePrintOrderTemplate, 'getPrintOrderOptionsContainerFor')
- def getPrintOrderOptionsContainerFor(self, ob) :
- """
- returns the printing options container or None.
- """
- if hasattr(aq_base(ob), PRINTING_OPTIONS_ID) :
- return getattr(ob, PRINTING_OPTIONS_ID)
-
- security.declareProtected(ManagePrintOrderTemplate, 'addPrintOrderTemplate')
- @postonly
- def addPrintOrderTemplate(self
- , ob
- , title=''
- , description=''
- , productReference=''
- , maxCopies=0
- , price=0
- , VATRate=0
- , REQUEST=None):
-
- title, maxCopies, price, VATRate = PhotoPrintTool._ckeckTemplateParams(title, maxCopies, price, VATRate)
-
- container = getattr(ob, PRINTING_OPTIONS_ID)
-
- id = makeValidId(container, title)
-
- factory = getUtility(IFactory, 'photoprint.order_template')
- orderTemplate = factory( id
- , title=title
- , description=description
- , productReference=productReference
- , maxCopies=maxCopies
- , price=price
- , VATRate=VATRate
- )
- container._setObject(id, orderTemplate)
- return orderTemplate.__of__(container)
-
-
- security.declareProtected(ManagePrintOrderTemplate, 'editPrintOrderTemplate')
- @postonly
- def editPrintOrderTemplate(self, ob, id, REQUEST=None, **kw):
- container = self.getPrintingOptionsContainerFor(ob)
- orderTemplate = getattr(container, id)
-
- g = kw.get
- title, description, productReference, maxCopies, price, VATRate = \
- g('title', ''), g('description', ''), g('productReference'), g('maxCopies',0), g('price',0), g('VATRate', 0)
- title, maxCopies, price, VATRate = PhotoPrintTool._ckeckTemplateParams(title, maxCopies, price, VATRate)
-
- orderTemplate.edit( title=title
- , description=description
- , productReference=productReference
- , maxCopies = maxCopies
- , price=price
- , VATRate=VATRate)
-
- return orderTemplate
-
- @staticmethod
- def _ckeckTemplateParams(title, maxCopies, price, VATRate) :
- title = title.strip()
-
- if not title :
- raise ValueError(_(u'You must enter a title.'))
- try :
- maxCopies = int(maxCopies)
- except ValueError :
- raise ValueError(_(u'You must enter an integer number\nfor the maximum number of copies.'))
- if maxCopies < 0 :
- raise ValueError(_(u'You must enter a positive value\nfor the maximum number of copies.'))
- try :
- price = float(price.replace(',', '.'))
- except ValueError :
- raise ValueError(_(u'You must enter a numeric value for the price.'))
-
- try :
- VATRate = float(VATRate.replace(',', '.')) / 100
- except ValueError :
- raise ValueError(_(u'You must enter a numeric value for the VAT rate.'))
-
- return title, maxCopies, price, VATRate
-
- security.declarePublic('addPrintOrder')
- def addPrintOrder(self, cart):
- utool = getToolByName(self, 'portal_url')
- portal = utool.getPortalObject()
- ttool = getToolByName(portal, 'portal_types')
-
- baseContainer = portal.unrestrictedTraverse(self.getProperty('incomingOrderPath'), None)
- if baseContainer is None:
- parts = self.getProperty('incomingOrderPath').split('/')
- baseContainer = portal
- for id in parts :
- if not hasattr(baseContainer.aq_base, id) :
- id = _sudo(lambda:ttool.constructContent('Order Folder', baseContainer, id))
- baseContainer = getattr(baseContainer, id)
-
- now = DateTime()
- monthId = now.strftime('%Y-%m')
- if not hasattr(baseContainer.aq_base, monthId) :
- monthId = _sudo(lambda:ttool.constructContent('Order Folder', baseContainer, monthId))
-
- container = getattr(baseContainer, monthId)
-
- self._order_counter += 1
- id = '%s-%d' % (monthId, self._order_counter)
- id = container.invokeFactory('Order', id)
- ob = getattr(container,id)
- ob.loadCart(cart)
- return ob
-
- security.declarePublic('getShippingFeesFor')
- def getShippingFeesFor(self, shippable=None, price=None):
- # returns Fees
- # TODO: use adapters
- # for the moment, shippable objet must provide a 'price' attribute
-
- if shippable and price :
- raise AttributeError("'shippable' and 'price' are mutually exclusive.")
-
- if shippable :
- amount = shippable.price.getValues()['taxed']
- else :
- amount = price.getValues()['taxed']
-
- threshold = self.getProperty('no_shipping_threshold')
-
- if amount < threshold :
- fees = Price(self.getProperty('shipping')
- , self.getProperty('shipping_vat'))
- else :
- fees = Price(0,0)
- return fees
-
- security.declarePrivate('getNextTransactionId')
- def getNextTransactionId(self):
- trid = self._transaction_id_counter
- trid = (trid + 1) % 1000000
- self._transaction_id_counter = trid
- trid = str(trid).zfill(6)
- return trid
-
-
-InitializeClass(PhotoPrintTool)
-
-
-class PrintingOptionsContainer(OrderedFolder) :
- meta_type = 'Printing options container'
- security = ClassSecurityInfo()
-
- def __init__(self) :
- self.id = PRINTING_OPTIONS_ID
-
- def __getitem__(self, k) :
- sd = context.session_data_manager.getSessionData(create = 1)