Bugfix : reduce sur une liste d'un élément provoque des effets de bords.
[photoprint.git] / cart.py
1 # -*- coding: utf-8 -*-
2 ####################################################
3 # Copyright © 2009 Luxia SAS. All rights reserved. #
4 # #
5 # Contributors: #
6 # - Benoît Pin <pinbe@luxia.fr> #
7 ####################################################
8 """ Cart definition used to store buyable prints
9
10 $Id$
11 $URL$
12 """
13 from Globals import InitializeClass, Persistent, PersistentMapping
14 from Acquisition import Implicit
15 from AccessControl import ModuleSecurityInfo
16 from Products.CMFCore.utils import getToolByName
17 from exceptions import SoldOutError, CartLockedError
18 from tool import COPIES_COUNTERS
19 from order import CopiesCounters
20
21 from logging import getLogger
22 console = getLogger('Products.photoprint.cart')
23
24 CART_ITEM_KEYS = ['cmf_uid', 'printing_template', 'quantity']
25
26 msecurity = ModuleSecurityInfo('Products.photoprint.cart')
27 msecurity.declarePublic('PrintCart')
28
29 class PrintCart(Persistent, Implicit) :
30 """
31 items are store like that:
32 {<uid>:
33 {<template>:quantity
34 ,...}
35 , ...
36 }
37 """
38
39 __allow_access_to_unprotected_subobjects__ = 1
40
41 def __init__(self) :
42 self._uids = PersistentMapping()
43 self._order = tuple() # products sequence order
44 self._shippingInfo = PersistentMapping()
45 self._confirmed = False
46 self.pendingOrderPath = ''
47
48 def setShippingInfo(self, **kw) :
49 self._shippingInfo.update(kw)
50
51 @property
52 def locked(self):
53 return self._confirmed
54
55 def append(self, context, item) :
56 if self.locked :
57 raise CartLockedError
58 assert isinstance(item, dict)
59 keys = item.keys()
60 keys.sort()
61 assert keys == CART_ITEM_KEYS
62
63 pptool = getToolByName(context, 'portal_photo_print')
64 uidh = getToolByName(context, 'portal_uidhandler')
65
66 uid = item['cmf_uid']
67 template = item['printing_template']
68 quantity = item['quantity']
69
70 photo = uidh.getObject(uid)
71 pOptions = pptool.getPrintingOptionsContainerFor(photo)
72 template = getattr(pOptions, template)
73 templateId = template.getId()
74
75 reference = template.productReference
76
77 # check / update counters
78 if template.maxCopies :
79 if not hasattr(photo.aq_base, COPIES_COUNTERS) :
80 setattr(photo, COPIES_COUNTERS, CopiesCounters())
81 counters = getattr(photo, COPIES_COUNTERS)
82 alreadySold = counters.get(reference)
83
84 if (alreadySold + quantity) > template.maxCopies :
85 raise SoldOutError(template.maxCopies - alreadySold)
86 else :
87 counters[reference] = alreadySold + quantity
88
89 if not self._uids.has_key(uid) :
90 self._uids[uid] = PersistentMapping()
91 self._order = self._order + (uid,)
92
93 if not self._uids[uid].has_key(templateId) :
94 self._uids[uid][templateId] = PersistentMapping()
95 self._uids[uid][templateId]['reference'] = reference
96 self._uids[uid][templateId]['quantity'] = 0
97
98 self._uids[uid][templateId]['quantity'] += quantity
99
100 def update(self, context, item) :
101 if self.locked :
102 raise CartLockedError
103 assert isinstance(item, dict)
104 keys = item.keys()
105 keys.sort()
106 assert keys == CART_ITEM_KEYS
107
108 pptool = getToolByName(context, 'portal_photo_print')
109 uidh = getToolByName(context, 'portal_uidhandler')
110
111 uid = item['cmf_uid']
112 template = item['printing_template']
113 quantity = item['quantity']
114
115 photo = uidh.getObject(uid)
116 pOptions = pptool.getPrintingOptionsContainerFor(photo)
117 template = getattr(pOptions, template)
118 templateId = template.getId()
119 reference = template.productReference
120
121 currentQuantity = self._uids[uid][templateId]['quantity']
122 delta = quantity - currentQuantity
123 if template.maxCopies :
124 counters = getattr(photo, COPIES_COUNTERS)
125 if delta > 0 :
126 already = counters[reference]
127 if (already + delta) > template.maxCopies :
128 raise SoldOutError(template.maxCopies - already)
129 counters[reference] += delta
130
131 self._uids[uid][templateId]['quantity'] += delta
132
133 def remove(self, context, uid, templateId) :
134 if self.locked :
135 raise CartLockedError
136 pptool = getToolByName(context, 'portal_photo_print')
137 uidh = getToolByName(context, 'portal_uidhandler')
138
139 photo = uidh.getObject(uid)
140 pOptions = pptool.getPrintingOptionsContainerFor(photo)
141 template = getattr(pOptions, templateId)
142 reference = template.productReference
143
144 quantity = self._uids[uid][templateId]['quantity']
145 if template.maxCopies :
146 counters = getattr(photo, COPIES_COUNTERS)
147 counters[reference] -= quantity
148
149 del self._uids[uid][templateId]
150 if not self._uids[uid] :
151 del self._uids[uid]
152 self._order = tuple([u for u in self._order if u != uid])
153
154
155 def __iter__(self) :
156 for uid in self._order :
157 item = {}
158 item['cmf_uid'] = uid
159 for templateId, rq in self._uids[uid].items() :
160 item['printing_template'] = templateId
161 item['quantity'] = rq['quantity']
162 yield item
163
164 def __nonzero__(self) :
165 return len(self._order) > 0
166