Commit dfd2109f authored by Nicolas Chauvat's avatar Nicolas Chauvat
Browse files

handle registration and payment (moved from cube euroscipy)

parent c7e59e70da56
......@@ -4,7 +4,7 @@
modname = 'cmt'
distname = 'cubicweb-cmt'
numversion = (0, 1, 0)
numversion = (0, 2, 0)
version = '.'.join(str(num) for num in numversion)
license = 'LCL'
......@@ -19,20 +19,16 @@ web = 'http://www.cubicweb.org/project/%s' % distname
pyversions = ['2.4']
__depends_cubes__ = {'conference': '>= 0.7.0',
'addressbook': None,
'blog': None,
'card': None,
#'cmcicpay': None,
'forgotpwd': ">= 0.2.0",
'registration': None,
'shoppingcart': '>= 0.2.2',
'tag': None,
}
__depends__ = {'cubicweb': '>= 3.9.0'}
for key, value in __depends_cubes__.items():
__depends__['cubicweb-'+key] = value
__use__ = tuple(__depends_cubes__)
__depends__ = {'cubicweb': '>= 3.9.0',
'cubicweb-blog': None,
'cubicweb-cmcicpay': None,
'cubicweb-conference': '>= 0.7.0',
'cubicweb-forgotpwd': '>= 0.2.0',
'cubicweb-openidrelay': None,
'cubicweb-registration': None,
'cubicweb-shoppingcart': '>= 0.2.2',
'cubicweb-tag': None,
}
# packaging ###
......
div.speaker {
font-style:italic;
}
div.description {
font-size:120%;
}
div.talktime {
font-style:italic;
}
span.dates {
font-size:80%;
font-style:italic;
}
table.talk {
width:100%;
}
.talktitle {
float: left;
}
.attendbutton {
margin-right:10px;
color:#FFFFFF;
font-size:10px;
margin-top:-18px;
text-align:center;
cursor: pointer;
width:170px;
}
/* #attend { */
/* background-color:#2EB85C; */
/* } */
/* #attend:hover { */
/* background-color:#2E965C; */
/* } */
/* #unattend { */
/* background-color:#7D7D7D; */
/* } */
/* #unattend:hover { */
/* background-color:#646464; */
/* } */
#attendanceComponent{
float:left;
}
#attendinfo {
font-size:11px;
font-weight: bold;
}
#attendcount {
margin-top:-4px;
font-size:10px;
font-weight: bold;
}
.toolbarButton{
display:block;
float:left;
}
#sponsorbox{
margin-right:10px;
}
#sponsorbox .sideBoxBody{
text-align:center;
background-color:#FFF;
}
#sponsorbox p {
padding:5px;
text-align:left;
font-size:1.1em;
font-family:verdana;
}
#sponsorbox img {
padding:10px;
}
.Gold img{
max-width: 90%;
}
.Silver img{
max-width: 80%;
}
.Bronze img{
max-width: 70%;
}
.Media img{
max-width: 70%;
}
.conferenceBox {
margin-bottom:14px;
padding:0px;
background:white;
border:1px solid #BBBBBB;
}
/* .conferenceBox a { */
/* color:#001240; */
/* } */
/* .conferenceBox a:hover { */
/* color:#D37E23; */
/* } */
.conferenceBox div {
padding: 2px 20px 2px 60px;
font-size:1.2em;
font-family:verdana;
font-weight: bold;
}
#confCallForPaper {
background:white;
background-image:url('icon_pen.gif');
background-repeat:no-repeat;
background-position:-20px 5px;
}
#confRegister {
background:white;
background-image:url('ticket-icon.png');
background-repeat:no-repeat;
background-position:-20px 5px;
}
#statreview {
margin:10px;
padding-left:10px;
border-left-style:solid;
border-left-width:5px;
border-left-color:red;
}
#stat ul {
list-style-type:circle;
list-style-position:inside;
}
#stat ul li {
background:none;
}
#statview ul li {
list-style-type:square;
}
#conftitle h1{
border-bottom: 0px;
}
\ No newline at end of file
add_cube('cmcicpay')
add_cube('openidrelay')
add_relation_definition('ShoppingCart', 'book_conf', 'Conference', ask_confirm=True)
add_relation_definition('Conference', 'has_shoppingitemtype', 'ShoppingItemType', ask_confirm=True)
sync_schema_props_perms('quantity')
......@@ -15,3 +15,20 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb-cmt schema"""
from yams.buildobjs import RelationDefinition
from cubes.shoppingcart.schema import ShoppingItem
ShoppingItem.get_relation('quantity').default = 1
class book_conf(RelationDefinition):
subject = 'ShoppingCart'
object = 'Conference'
cardinality = '1*'
class has_shoppingitemtype(RelationDefinition):
subject = 'Conference'
object = 'ShoppingItemType'
cardinality = '*1'
......@@ -15,3 +15,187 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb-cmt views/forms/actions/components for web ui"""
import datetime
from logilab.mtconverter import xml_escape
from cubicweb.web import uicfg, box, Redirect
from cubicweb.view import EntityView
from cubicweb.selectors import is_instance, match_user_groups, authenticated_user
from cubicweb.web.views import primary, workflow
from cubes.conference.views.forms import subject_reg_open_conf_vocabulary
from cubes.shoppingcart.views import ShoppingCartPrimaryView
uicfg.autoform_field_kwargs.tag_subject_of(('ShoppingCart', 'book_conf', 'Conference'),
{'choices': subject_reg_open_conf_vocabulary})
uicfg.actionbox_appearsin_addmenu.tag_subject_of(('Conference', 'has_shoppingitemtype', '*'), True)
_ = unicode
from cubes.shoppingcart.views import ShoppingCartEntityFormRenderer
# this message is needed to have it appear in translation files
_('creating ShoppingCart (ShoppingCart buyer CWUser %(linkto)s)')
REPLACE_LIST = []
class ConferenceRegistrationBox(box.BoxTemplate):
__regid__ = 'confregistrationbox'
context = 'left'
title = _(u'Conference Registration')
order = 0
def call(self, **kwargs):
reg_open = self._cw.execute('Any C WHERE C is Conference, C reg_open "True"')
if not reg_open:
return
conf = reg_open.get_entity(0,0) # XXX bug: what if there is more than one conf ?
w = self.w
register_now = self._cw._('Register now for the conference !')
pay_to_confirm = self._cw._('Pay now to confirm your registration !')
you_are_registered = self._cw._('You are registered for the conference')
label = None
if self._cw.session.anonymous_session:
if reg_open:
label = register_now
else:
has_cart = self._cw.execute('Any C WHERE U eid %(x)s, C buyer U', {'x': self._cw.user.eid})
items = self._cw.execute('Any I WHERE U eid %(x)s, C buyer U, C items_in_cart I',
{'x': self._cw.user.eid})
if has_cart:
if items:
if has_cart.get_entity(0,0).in_state[0].name == 'checked out':
label = you_are_registered
else:
label = pay_to_confirm
else:
label = register_now
elif reg_open:
label = register_now
if label:
w(u'<div class="conferenceBox">')
w(u'<div id="confRegister">')
w(u'<a href="%s">%s</a>' % (xml_escape(conf.absolute_url()+'/registration'), xml_escape(label)))
w(u'</div></div>')
class CmtShoppingCartEntityFormRenderer(ShoppingCartEntityFormRenderer):
explanation_text = _(u'To register for the conference, add to your shopping '
'cart the admission fees listed below.')
REPLACE_LIST.append((CmtShoppingCartEntityFormRenderer, ShoppingCartEntityFormRenderer))
from cubes.cmcicpay import cmcic
from cubes.cmcicpay.views import get_tpe
class CmtShoppingCartPrimaryView(ShoppingCartPrimaryView):
def reg_state(self, entity):
if entity.items_in_cart:
if entity.in_state[0].name == 'in progress':
return 'not payed for'
return 'confirmed'
else:
return 'empty'
def render_entity_title(self, entity):
reg = self.reg_state(entity)
conf = entity.book_conf[0]
title = self._cw._('Your registration to %s is %s') % (conf.dc_title(), reg)
self.w(u'<h1>%s (#%s)</h1>' % (xml_escape(title), entity.eid))
def render_entity_relations(self, entity):
super(CmtShoppingCartPrimaryView, self).render_entity_relations(entity)
reg = self.reg_state(entity)
btn_modify = (u'<div><a href="%s">%s</a></div>' % (
self._cw.build_url(entity.eid, vid='edition'),
self._cw._('modify your registration')))
if reg == 'not payed for':
total = sum(item.quantity*item.item.price for item in entity.items_in_cart)
tpe = get_tpe(self._cw)
payreq = cmcic.PaymentRequest()
payreq.reference = str(entity.eid)
payreq.amount = "%.2f" % total
payreq.currency = "EUR"
payreq.description = "Some Conference 2010" # XXX FIXME use title of conference
payreq.date = datetime.datetime.now().strftime("%d/%m/%Y:%H:%M:%S")
payreq.lang = "EN"
#payreq.email = entity.buyer[0].primary_email
payreq.email = "test@test.zz"
payreq.url_root = self._cw.base_url()
payreq.url_ok = entity.absolute_url(__message='The payment succeeded.')
payreq.url_err = entity.absolute_url(__message='The payment failed.')
label = self._cw._('pay now %s %s to confirm your registration') % (
payreq.amount, payreq.currency)
icon = u'<img alt="OK_ICON" src="%s"/>' % self._cw.external_resource('OK_ICON')
submit = u'<button type="submit" class="validateButton">%s %s</button>' % (icon, label)
self.w(u'<table width="100%%"><tr><td>%s</td><td>%s</td></tr></table>' % (
cmcic.html_form(tpe, payreq, submit),
btn_modify))
elif reg == 'empty':
self.w(u'<br /><p style="background-color: #F5E5EE;">')
self.w(self._cw._('You have not added admission fees for the conference or the tutorials to this shopping cart.<br />'
'You are <b>NOT REGISTERED</b> at this point.'))
self.w(u'</p>')
self.w(btn_modify)
else:
conf = entity.book_conf[0]
self.w(u'<p><a href="%s">%s</a></p>' % (conf.absolute_url(), self._cw._('Go to the conference schedule')))
REPLACE_LIST.append((CmtShoppingCartPrimaryView, ShoppingCartPrimaryView))
# registration view
class ConfRegistrationView(EntityView):
__regid__ = 'conf-registration'
__select__ = EntityView.__select__ & is_instance('Conference')
def cell_call(self, row, col):
entity = self.cw_rset.get_entity(row, col)
self.w(u'<h1>Registration for conference %s</h1>' % entity.dc_title())
self.w(u'<div>%s</div>' % self._cw._(
'You need to create an account and sign in '
'before you can book the conference'))
view = self._cw.vreg['views'].select('login_or_register', self._cw)
self.w(view.render()) # XXX adding title=False)) requires changing conference
class ConfRegistrationAuthView(EntityView):
__regid__ = 'conf-registration'
__select__ = EntityView.__select__ & is_instance('Conference') & authenticated_user()
def cell_call(self, row, col):
entity = self.cw_rset.get_entity(row, col)
rset = self._cw.execute('Any S WHERE S buyer U, S book_conf C, U eid %(u)s, C eid %(c)s',
{'u': self._cw.user.eid, 'c': entity.eid})
if rset:
entity = rset.get_entity(0,0)
url = entity.absolute_url()
else:
linkto = 'buyer:%s:subject' % self._cw.user.eid
url = self._cw.build_url('add/ShoppingCart', __linkto=linkto)
raise Redirect(url)
## urls
from cubicweb.web.views.urlrewrite import SimpleReqRewriter, rgx
class ConfRewrite(SimpleReqRewriter):
rules = [
(rgx('/conference/(\d+)'),
dict(rql='Any C WHERE C is Conference, C eid "%(eid)s"' % {'eid': r'\1'})),
(rgx('/conference/([^/]+)'),
dict(rql='Any C WHERE C is Conference, C url_id "%(id)s"' % {'id': r'\1'})),
(rgx('/conference/([^/]+)/registration'),
dict(rql='Any C WHERE C is Conference, C url_id "%(id)s"' % {'id': r'\1'},
vid='conf-registration')),
(rgx('/conference/([^/]+)/([A-Za-z]+)'),
dict(rql='Any C WHERE C is Conference, C url_id "%(id)s"' % {'id': r'\1'},
selected_tab=r'\2', tab=r'\2')),
]
def registration_callback(vreg):
vreg.register_all(globals().values(), __name__, [new for new,old in REPLACE_LIST])
for new, old in REPLACE_LIST:
vreg.register_and_replace(new, old)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment