1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # POS Membership module for OpenERP, Manage membership payments from POS.
5 # Copyright (C) 2013 L'Heureux Cyclage (<http://www.heureux-cyclage.org>)
7 # This file is a part of POS Membership
9 # POS Membership is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # ReMembership is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ##############################################################################
23 from openerp
import netsvc
24 from openerp
.osv
import fields
, osv
25 from openerp
.tools
.translate
import _
27 from datetime
import datetime
, date
28 from dateutil
.relativedelta
import relativedelta
32 ('none', 'Non Member'),
33 ('canceled', 'Cancelled Member'),
34 ('old', 'Old Member'),
35 ('waiting', 'Waiting Member'),
36 ('invoiced', 'Invoiced Member'),
37 ('free', 'Free Member'),
38 ('paid', 'Paid Member'),
41 class pos_order(osv
.osv
):
42 _inherit
= 'pos.order'
44 def create_partner_from_ui(self
, cr
, uid
, partners
, context
=None):
45 print ("DEV: [pos_membership] [create_partner_from_ui] partners=%s" % str(partners
))
47 partner_obj
= self
.pool
.get('res.partner')
48 for tmp_partner
in partners
:
49 partner
= tmp_partner
['data']
50 partner_id
= partner_obj
.create(cr
, uid
, {
51 'name': partner
['name'],
53 partner_ids
.append(partner_id
)
54 #self.signal_paid(cr, uid, [partner_id])
57 def create_from_ui(self
, cr
, uid
, orders
, context
=None):
58 # NOTE: copied from openerp/addons/point_of_sale/point_of_sale.py
59 #_logger.info("orders: %r", orders)
60 print ("DEV: [pos_membership] [create_from_ui] order=", str(orders
))
62 for tmp_order
in orders
:
63 order
= tmp_order
['data']
64 order_id
= self
.create(cr
, uid
, {
65 'name': order
['name'],
66 'user_id': order
['user_id'] or False,
67 'session_id': order
['pos_session_id'],
68 'lines': order
['lines'],
69 'pos_reference':order
['name'],
70 #-- BEGIN pos_membership
71 'partner_id':order
['partner_id'],
72 #-- END pos_membership
75 for payments
in order
['statement_ids']:
77 self
.add_payment(cr
, uid
, order_id
, {
78 'amount': payment
['amount'] or 0.0,
79 'payment_date': payment
['name'],
80 'statement_id': payment
['statement_id'],
81 'payment_name': payment
.get('note', False),
82 'journal': payment
['journal_id']
85 if order
['amount_return']:
86 session
= self
.pool
.get('pos.session').browse(cr
, uid
, order
['pos_session_id'], context
=context
)
87 cash_journal
= session
.cash_journal_id
88 cash_statement
= False
90 cash_journal_ids
= filter(lambda st
: st
.journal_id
.type=='cash', session
.statement_ids
)
91 if not len(cash_journal_ids
):
92 raise osv
.except_osv( _('error!'),
93 _("No cash statement found for this session. Unable to record returned cash."))
94 cash_journal
= cash_journal_ids
[0].journal_id
95 self
.add_payment(cr
, uid
, order_id
, {
96 'amount': -order
['amount_return'],
97 'payment_date': time
.strftime('%Y-%m-%d %H:%M:%S'),
98 'payment_name': _('return'),
99 'journal': cash_journal
.id,
101 order_ids
.append(order_id
)
102 wf_service
= netsvc
.LocalService("workflow")
103 wf_service
.trg_validate(uid
, 'pos.order', order_id
, 'paid', cr
)
108 class membership_line(osv
.osv
):
110 _inherit
= 'membership.membership_line'
112 def _get_partners(self
, cr
, uid
, ids
, context
=None):
113 list_membership_line
= []
114 member_line_obj
= self
.pool
.get('membership.membership_line')
115 for partner
in self
.pool
.get('res.partner').browse(cr
, uid
, ids
, context
=context
):
116 if partner
.member_lines
:
117 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('id', 'in', [ l
.id for l
in partner
.member_lines
])], context
=context
)
118 print("DEV: [pos_membership] [membership_line] [_get_partners]: ids=%s res=%s" % (str(ids
), str(list_membership_line
)))
119 return list_membership_line
121 #def _get_membership_lines_from_account_invoice(self, cr, uid, ids, context=None):
122 # list_membership_line = []
123 # member_line_obj = self.pool.get('membership.membership_line')
124 # for invoice in self.pool.get('account.invoice').browse(cr, uid, ids, context=context):
125 # if invoice.invoice_line:
126 # list_membership_line += member_line_obj.search(cr, uid, [('account_invoice_line', 'in', [ l.id for l in invoice.invoice_line])], context=context)
128 # { 'class': 'account.invoice'
129 # , 'ids': list_membership_line
131 # #res= list_membership_line
132 # print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_account_invoice]: res=%s" % str(res))
134 def _get_membership_lines_from_pos_order(self
, cr
, uid
, ids
, context
=None):
135 list_membership_line
= []
136 member_line_obj
= self
.pool
.get('membership.membership_line')
137 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: ids=%s context=%s" % (str(ids
), str(context
)))
138 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
140 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('pos_order_line', 'in', [ l
.id for l
in order
.lines
])], context
=context
)
142 # { 'class': 'pos.order'
143 # , 'ids': list_membership_line
145 res
= list_membership_line
146 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: res=%s" % str(res
))
149 def _check_membership_date(self
, cr
, uid
, ids
, context
=None):
150 """Check if membership product is not in the past
151 @param self: The object pointer
152 @param cr: the current row, from the database cursor,
153 @param uid: the current user’s ID for security checks,
154 @param ids: List of Membership Line IDs
155 @param context: A standard dictionary for contextual values
159 SELECT MIN(ml.date_to - ai.date_invoice)
160 FROM membership_membership_line ml
161 JOIN account_invoice_line ail ON (
162 ml.account_invoice_line = ail.id
164 JOIN account_invoice ai ON (
165 ai.id = ail.invoice_id)
166 WHERE ml.id IN %s''', (tuple(ids
),))
169 if r
[0] and r
[0] < 0:
172 SELECT MIN(ml.date_to - ai.date_order)
173 FROM membership_membership_line ml
174 JOIN pos_order_line ail ON (
175 ml.pos_order_line = ail.id
177 JOIN pos_order ai ON (
178 ai.id = ail.order_id)
179 WHERE ml.id IN %s''', (tuple(ids
),))
182 if r
[0] and r
[0] < 0:
186 def _state(self
, cr
, uid
, ids
, name
, args
, context
=None):
187 """Compute the state lines
188 @param self: The object pointer
189 @param cr: the current row, from the database cursor,
190 @param uid: the current user’s ID for security checks,
191 @param ids: List of Membership Line IDs
192 @param name: Field Name
193 @param context: A standard dictionary for contextual values
194 @param return: Dictionary of state Value
197 print("DEV: [pos_membership] [membership_line] [_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
198 inv_obj
= self
.pool
.get('account.invoice')
199 ord_obj
= self
.pool
.get('pos.order')
200 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
202 SELECT i.state, i.id FROM
206 SELECT l.invoice_id FROM
207 account_invoice_line l WHERE
209 SELECT ml.account_invoice_line FROM
210 membership_membership_line ml WHERE
215 fetched
= cr
.fetchone()
219 if (istate
== 'draft') |
(istate
== 'proforma'):
221 elif istate
== 'open':
223 elif istate
== 'paid':
225 inv
= inv_obj
.browse(cr
, uid
, fetched
[1], context
=context
)
226 for payment
in inv
.payment_ids
:
227 if payment
.invoice
and payment
.invoice
.type == 'out_refund':
229 elif istate
== 'cancel':
234 SELECT i.state, i.id, i.partner_id FROM
238 SELECT l.order_id FROM
239 pos_order_line l WHERE
241 SELECT ml.pos_order_line FROM
242 membership_membership_line ml WHERE
247 fetched
= cr
.fetchone()
249 res
[line
.id] = 'canceled'
251 partner_id
= fetched
[2]
252 self
.write(cr
, uid
, line
.id, {'partner': partner_id
})
253 # NOTE: force une mise à jour du partner,
254 # car il n'y en a pas lors de la création du pos.order
255 # dans le PoS (pour le moment)
256 partner_obj
= self
.pool
.get('res.partner')
257 for partner
in partner_obj
.browse(cr
, uid
, [partner_id
], context
=context
):
258 if not partner
.member_ident
:
259 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
260 partner_obj
.write(cr
, uid
, partner
.id, {'member_ident': mbr_id
})
263 if (ostate
== 'paid') |
(ostate
== 'draft'):
265 elif (ostate
== 'done') |
(ostate
== 'invoiced'):
267 # XXX: regarder l'équivalent de out_refund pour un pos.order
268 print("DEV: [pos_membership] [membership_line] [_state]: paid: TODO")
269 #inv = ord_obj.browse(cr, uid, fetched[1], context=context)
270 #for payment in inv.payment_ids:
271 # if payment.invoice and payment.invoice.type == 'out_refund':
273 elif ostate
== 'cancel':
276 print("DEV: [pos_membership] [membership_line] [_state]: return=%s" % (str(res
)))
279 def write(self
, cr
, uid
, ids
, vals
, context
=None):
280 print("DEV: [pos_membership] [membership_line] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
281 member_line_obj
= self
.pool
.get('membership.membership_line')
282 res
= super(membership_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
283 print("DEV: [pos_membership] [membership_line] [write]: res=%s" % str(res
))
286 def create(self
, cr
, uid
, vals
, context
=None):
287 print("DEV: [pos_membership] [membership_line] [create]: vals=%s" % (str(vals
)))
288 member_line_obj
= self
.pool
.get('membership.membership_line')
289 res
= super(membership_line
, self
).create(cr
, uid
, vals
, context
=context
)
290 print("DEV: [pos_membership] [membership_line] [create]: res=%s" % (str(res
)))
294 'pos_order_line': fields
.many2one('pos.order.line', 'POS Order line', readonly
=True),
295 'pos_order_id': fields
.related('pos_order_line', 'order_id', type='many2one', relation
='pos.order', string
='Order', readonly
=True),
296 'state': fields
.function(_state
,
297 string
='Membership Status', type='selection',
300 #'account.invoice': (_get_membership_lines_from_account_invoice, ['state'], 10),
301 # NOTE: déjà géré par membership.membership_line._get_membership_lines
302 'pos.order': (_get_membership_lines_from_pos_order
, ['state', 'partner_id'], 10),
303 'res.partner': (_get_partners
, ['membership_state'], 12),
304 }, help="""It indicates the membership status.
305 -Non Member: A member who has not applied for any membership.
306 -Cancelled Member: A member who has cancelled his membership.
307 -Old Member: A member whose membership date has expired.
308 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
309 -Invoiced Member: A member whose invoice has been created.
310 -Paid Member: A member who has paid the membership amount."""),
311 'company_id': fields
.related('account_invoice_line', 'invoice_id', 'company_id', type="many2one", relation
="res.company", string
="Company", readonly
=True, store
=True)
312 # XXX: pos_order_line a aussi un company_id
317 class Partner(osv
.osv
):
319 _inherit
= 'res.partner'
321 def _get_partner_id(self
, cr
, uid
, ids
, context
=None):
322 print("DEV: [pos_membership] [Partner] [_get_partner_id]: ids=%s context=%s" % (str(ids
), str(context
)))
323 member_line_obj
= self
.pool
.get('membership.membership_line')
324 res_obj
= self
.pool
.get('res.partner')
325 data_inv
= member_line_obj
.browse(cr
, uid
, ids
, context
=context
)
327 for data
in data_inv
:
328 list_partner
.append(data
.partner
.id)
331 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
333 print("DEV: [pos_membership] [Partner] [_get_partner_id]: res=%s" % (str(list_partner
)))
336 def _get_invoice_partner(self
, cr
, uid
, ids
, context
=None):
337 inv_obj
= self
.pool
.get('account.invoice')
338 res_obj
= self
.pool
.get('res.partner')
339 data_inv
= inv_obj
.browse(cr
, uid
, ids
, context
=context
)
341 for data
in data_inv
:
342 list_partner
.append(data
.partner_id
.id)
345 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
349 def _get_order_partner(self
, cr
, uid
, ids
, context
=None):
350 ord_obj
= self
.pool
.get('pos.order')
351 res_obj
= self
.pool
.get('res.partner')
352 data_ord
= ord_obj
.browse(cr
, uid
, ids
, context
=context
)
354 for data
in data_ord
:
355 list_partner
.append(data
.partner_id
.id)
358 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
362 def _membership_state(self
, cr
, uid
, ids
, name
, args
, context
=None):
363 """This Function return Membership State For Given Partner.
364 @param self: The object pointer
365 @param cr: the current row, from the database cursor,
366 @param uid: the current user’s ID for security checks,
367 @param ids: List of Partner IDs
368 @param name: Field Name
369 @param context: A standard dictionary for contextual values
370 @param return: Dictionary of Membership state Value
373 print("DEV: [pos_membership] [Partner] [_membership_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
376 today
= time
.strftime('%Y-%m-%d')
378 print("DEV: [pos_membership] [Partner] [_membership_state] id=%s" % (str(id)))
379 partner_data
= self
.browse(cr
, uid
, id, context
=context
)
380 if partner_data
.membership_cancel
and today
> partner_data
.membership_cancel
:
383 if partner_data
.membership_stop
and today
> partner_data
.membership_stop
:
387 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines] [test]")
388 if partner_data
.member_lines
:
389 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines]" % ())
390 for mline
in partner_data
.member_lines
:
391 print("DEV: [pos_membership] [Partner] [_membership_state] [mline]: id=%s" % str(mline
.id))
392 if mline
.date_to
>= today
:
393 if mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
:
394 istate
= mline
.account_invoice_line
.invoice_id
.state
395 print("DEV: [pos_membership] [Partner] [_membership_state] [account_invoice_line]: id=%s istate=%s" % (str(mline
.account_invoice_line
.invoice_id
.id), str(istate
)))
398 inv
= mline
.account_invoice_line
.invoice_id
399 for payment
in inv
.payment_ids
:
400 if payment
.invoice
.type == 'out_refund':
403 elif istate
== 'open' and s
!=0:
405 elif istate
== 'cancel' and s
!=0 and s
!=1:
407 elif (istate
== 'draft' or istate
== 'proforma') and s
!=0 and s
!=1:
409 elif mline
.pos_order_line
and mline
.pos_order_line
.order_id
:
410 ostate
= mline
.pos_order_line
.order_id
.state
411 print("DEV: [pos_membership] [Partner] [_membership_state] [pos_order_line]: id=%s ostate=%s" % (str(mline
.pos_order_line
.order_id
.id), str(ostate
)))
412 if ostate
== 'paid' and s
!=0 and s
!=1:
414 if ostate
== 'invoiced':
418 # XXX: regarder l'équivalent de out_refund pour un pos.order
419 print("DEV: [pos_membership] [partner] [_membership_state]: paid: TODO")
420 #inv = mline.pos_order_line.order_id
421 #for payment in inv.payment_ids:
422 # if payment.invoice.type == 'out_refund':
425 elif ostate
== 'open' and s
!=0:
426 # XXX: 1 donne invoiced, c'est pitet pas bon
427 print("DEV: [pos_membership] [partner] [_membership_state]: invoiced: TODO")
429 elif ostate
== 'cancel' and s
!=0 and s
!=1:
431 elif ostate
== 'draft' and s
!=0 and s
!=1:
434 for mline
in partner_data
.member_lines
:
435 if mline
.date_from
< today
and \
436 mline
.date_to
< today
and \
437 mline
.date_from
<= mline
.date_to
and \
438 ( (mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
.state
) == 'paid' or \
439 ( mline
.pos_order_line
and \
440 ( mline
.pos_order_line
.order_id
.state
== 'paid' or \
441 mline
.pos_order_line
.order_id
.state
== 'done' or \
442 mline
.pos_order_line
.order_id
.state
== 'invoiced' ))):
458 if partner_data
.free_member
and s
!=0:
460 if partner_data
.associate_member
:
461 res_state
= self
._membership
_state
(cr
, uid
, [partner_data
.associate_member
.id], name
, args
, context
=context
)
462 res
[id] = res_state
[partner_data
.associate_member
.id]
463 print("DEV: [pos_membership] [Partner] [_membership_state]: res=%s" % (str(res
)))
466 def _membership_date(self
, cr
, uid
, ids
, name
, args
, context
=None):
467 """Return date of membership"""
470 member_line_obj
= self
.pool
.get('membership.membership_line')
471 print("DEV: [pos_membership] [Partner] [_membership_date]: ids=%s" % (str(ids
)))
472 for partner
in self
.browse(cr
, uid
, ids
, context
=context
):
473 if partner
.associate_member
:
474 partner_id
= partner
.associate_member
.id
476 partner_id
= partner
.id
478 'membership_start': False,
479 'membership_stop': False,
480 'membership_cancel': False
482 if name
== 'membership_start':
483 line_id
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
484 limit
=1, order
='date_from', context
=context
)
486 res
[partner
.id]['membership_start'] = member_line_obj
.read(cr
, uid
, line_id
[0],
487 ['date_from'], context
=context
)['date_from']
488 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_start]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_start'])))
490 if name
== 'membership_stop':
491 line_id1
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
492 limit
=1, order
='date_to desc', context
=context
)
494 res
[partner
.id]['membership_stop'] = member_line_obj
.read(cr
, uid
, line_id1
[0],
495 ['date_to'], context
=context
)['date_to']
496 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_stop]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_stop'])))
498 if name
== 'membership_cancel':
499 if partner
.membership_state
== 'canceled':
500 line_id2
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner
.id)], limit
=1, order
='date_cancel', context
=context
)
502 res
[partner
.id]['membership_cancel'] = member_line_obj
.read(cr
, uid
, line_id2
[0], ['date_cancel'], context
=context
)['date_cancel']
503 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_cancel]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_cancel'])))
504 print("DEV: [pos_membership] [Partner] [_membership_date]: res=%s" % (str(res
)))
507 def _get_partners(self
, cr
, uid
, ids
, context
=None):
510 ids2
= self
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
514 def __get_membership_state(self
, *args
, **kwargs
):
515 return self
._membership
_state
(*args
, **kwargs
)
518 'membership_state': fields
.function(
519 __get_membership_state
,
520 string
= 'Current Membership Status', type = 'selection',
523 # NOTE: il est important que la priorité soit plus grande
524 # que les membership_{start,stop,cancel}
525 # car _membership_state s'en sert et doit donc les trouver à jour.
526 'account.invoice': (_get_invoice_partner
, ['state'], 20),
527 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 20),
528 'membership.membership_line': (_get_partner_id
, ['state'], 20),
529 'res.partner': (_get_partners
, ['free_member', 'membership_state', 'associate_member'], 20)
530 }, help="""It indicates the membership state.
531 -Non Member: A partner who has not applied for any membership.
532 -Cancelled Member: A member who has cancelled his membership.
533 -Old Member: A member whose membership date has expired.
534 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
535 -Invoiced Member: A member whose invoice has been created.
536 -Paying member: A member who has paid the membership fee."""),
537 'membership_start': fields
.function(
538 _membership_date
, multi
= 'membership_start',
539 string
= 'Membership Start Date', type = 'date',
541 'account.invoice': (_get_invoice_partner
, ['state'], 10),
542 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
543 'membership.membership_line': (_get_partner_id
, ['state'], 10),
544 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
545 }, help="Date from which membership becomes active."),
546 'membership_stop': fields
.function(
548 string
= 'Membership End Date', type='date', multi
='membership_stop',
550 'account.invoice': (_get_invoice_partner
, ['state'], 10),
551 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
552 'membership.membership_line': (_get_partner_id
, ['state'], 10),
553 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
554 }, help="Date until which membership remains active."),
555 'membership_cancel': fields
.function(
557 string
= 'Cancel Membership Date', type='date', multi
='membership_cancel',
559 'account.invoice': (_get_invoice_partner
, ['state'], 11),
560 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 11),
561 'membership.membership_line': (_get_partner_id
, ['state'], 10),
562 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
563 }, help="Date on which membership has been cancelled"),
568 class pos_order(osv
.osv
):
569 _inherit
= 'pos.order'
571 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py
572 def action_invoice(self
, cr
, uid
, ids
, context
=None):
573 print ("DEV: [pos_membership] [pos_order] [action_invoice]")
574 wf_service
= netsvc
.LocalService("workflow")
575 inv_ref
= self
.pool
.get('account.invoice')
576 inv_line_ref
= self
.pool
.get('account.invoice.line')
577 product_obj
= self
.pool
.get('product.product')
580 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
582 inv_ids
.append(order
.invoice_id
.id)
585 if not order
.partner_id
:
586 raise osv
.except_osv(_('Error!'), _('Please provide a partner for the sale.'))
588 acc
= order
.partner_id
.property_account_receivable
.id
589 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py to fix account.invoice.line creation
592 'origin': order
.name
,
594 'journal_id': order
.sale_journal
.id or None,
595 'type': 'out_invoice',
596 'reference': order
.name
,
597 'partner_id': order
.partner_id
.id,
598 'comment': order
.note
or '',
599 'currency_id': order
.pricelist_id
.currency_id
.id, # considering partner's sale pricelist's currency
602 inv
.update(inv_ref
.onchange_partner_id(cr
, uid
, [], 'out_invoice', order
.partner_id
.id)['value'])
603 if not inv
.get('account_id', None):
604 inv
['account_id'] = acc
605 for line
in order
.lines
:
607 #'invoice_id': inv_id,
608 'product_id': line
.product_id
.id,
609 'quantity': line
.qty
,
611 inv_name
= product_obj
.name_get(cr
, uid
, [line
.product_id
.id], context
=context
)[0][1]
612 inv_line
.update(inv_line_ref
.product_id_change(cr
, uid
, [],
614 line
.product_id
.uom_id
.id,
615 line
.qty
, partner_id
= order
.partner_id
.id,
616 fposition_id
=order
.partner_id
.property_account_position
.id)['value'])
617 if line
.product_id
.description_sale
:
618 inv_line
['note'] = line
.product_id
.description_sale
619 inv_line
['price_unit'] = line
.price_unit
620 inv_line
['discount'] = line
.discount
621 inv_line
['name'] = inv_name
622 inv_line
['invoice_line_tax_id'] = ('invoice_line_tax_id' in inv_line
)\
623 and [(6, 0, inv_line
['invoice_line_tax_id'])] or []
624 #inv_line_ref.create(cr, uid, inv_line, context=context)
625 inv
['invoice_line'].append((0, 0, inv_line
))
626 inv_id
= inv_ref
.create(cr
, uid
, inv
, context
=context
)
628 self
.write(cr
, uid
, [order
.id], {'invoice_id': inv_id
, 'state': 'invoiced'}, context
=context
)
629 inv_ref
.confirm_paid(cr
, uid
, [inv_id
], context
=context
)
630 inv_ids
.append(inv_id
)
631 inv_ref
.button_reset_taxes(cr
, uid
, [inv_id
], context
=context
)
632 wf_service
.trg_validate(uid
, 'pos.order', order
.id, 'invoice', cr
)
634 if not inv_ids
: return {}
636 mod_obj
= self
.pool
.get('ir.model.data')
637 res
= mod_obj
.get_object_reference(cr
, uid
, 'account', 'invoice_form')
638 res_id
= res
and res
[1] or False
640 'name': _('Customer Invoice'),
644 'res_model': 'account.invoice',
645 'context': "{'type':'out_invoice'}",
646 'type': 'ir.actions.act_window',
649 'res_id': inv_ids
and inv_ids
[0] or False,
652 def write(self
, cr
, uid
, ids
, vals
, context
=None):
653 print("DEV: [pos_membership] [pos_order] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
654 pos_order_obj
= self
.pool
.get('pos.order')
655 res
= super(pos_order
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
656 print("DEV: [pos_membership] [pos_order] [write]: res=%s" % str(res
))
659 def create(self
, cr
, uid
, vals
, context
=None):
660 print("DEV: [pos_membership] [pos_order] [create]: vals=%s" % (str(vals
)))
661 pos_order_obj
= self
.pool
.get('pos.order')
662 res
= super(pos_order
, self
).create(cr
, uid
, vals
, context
=context
)
663 print("DEV: [pos_membership] [pos_order] [create]: res=%s" % (str(res
)))
668 class pos_order_line(osv
.osv
):
669 _inherit
= 'pos.order.line'
671 def write(self
, cr
, uid
, ids
, vals
, context
=None):
672 print("DEV: [pos_membership] [pos_order_line] [write]: ids=%s vals=%s context=%s" % (str(ids
), str(vals
), str(context
)))
673 member_line_obj
= self
.pool
.get('membership.membership_line')
674 res
= super(pos_order_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
675 print ("DEV: [pos_membership] [pos_order_line] [write] [super] : res=%s" % str(res
))
676 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
677 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
678 if line
.product_id
and line
.product_id
.membership
and not ml_ids
:
679 date_from
= line
.product_id
.membership_date_from
680 date_to
= line
.product_id
.membership_date_to
681 if line
.order_id
.date_order
> date_from
and \
682 line
.order_id
.date_order
< date_to
:
683 date_from
= line
.order_id
.date_order
684 if line
.product_id
.membership_date2date
:
685 date_from
= ('date_from' in context
686 and context
['date_from']
687 and datetime
.strptime(context
['date_from'], "%Y-%m-%d")
689 date_to
= date_from
+ relativedelta(months
= +12) # TODO: parameterize this delta?
690 date_from
= date_from
.strftime("%Y-%m-%d")
691 date_to
= date_to
.strftime("%Y-%m-%d")
692 print ("DEV: [pos_membership] [write] date_from: %s" % str(date_from
))
693 print ("DEV: [pos_membership] [write] date_to : %s" % str(date_to
))
694 member_line_obj
.create(cr
, uid
695 , { 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False
696 , 'membership_id': line
.product_id
.id
697 , 'member_price': line
.price_unit
698 , 'date': time
.strftime('%Y-%m-%d')
699 , 'date_from': date_from
701 , 'pos_order_line': line
.id
704 if line
.product_id
.membership_grouped
:
705 if line
.order_id
.partner_id
.associate_members
:
706 associate_member_line_ids
= member_line_obj
.search(cr
, uid
707 , [ ('pos_order_line', '=', line
.id)
708 , ('partner', '!=', line
.order_id
.partner_id
.id)
711 for associate_member_line
in member_line_obj
.browse(cr
, uid
, associate_member_line_ids
, context
=context
):
712 print ("DEV: [pos_membership] [write] [associate] date_from: %s" % str(date_from
))
713 print ("DEV: [pos_membership] [write] [associate] date_to : %s" % str(date_to
))
714 member_line_obj
.write(cr
, uid
, associate_member_line
.id
715 , {'date_from': date_from
720 print("DEV: mettre une contrainte pour l'objet\
721 membership.membership_line interdisant les\
722 adhésions groupées reliées à des partenaires\
723 sans membres associés")
725 associate_member_line_ids
= member_line_obj
.search(cr
, uid
726 , [ ('pos_order_line', '=', line
.id)
727 , ('partner', '!=', line
.order_id
.partner_id
.id)
730 member_line_obj
.unlink(cr
, uid
, associate_member_line_ids
, context
=context
)
732 #Define member ident if it's necessary
733 partners
= [line
.order_id
.partner_id
]
734 if line
.order_id
.partner_id
.associate_members
:
735 partners
.extend(line
.order_id
.partner_id
.associate_members
)
737 if not i
.member_ident
:
738 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
739 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
740 if line
.product_id
and not line
.product_id
.membership
and ml_ids
:
741 # Product line has changed to a non membership product
742 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
743 print("DEV: [pos_membership] [pos_order_line] [write]: res=%s" % str(res
))
746 def unlink(self
, cr
, uid
, ids
, context
=None):
747 """Remove Membership Line Record for Account Invoice Line
749 member_line_obj
= self
.pool
.get('membership.membership_line')
751 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', id)], context
=context
)
752 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
753 return super(pos_order_line
, self
).unlink(cr
, uid
, ids
, context
=context
)
755 def create(self
, cr
, uid
, vals
, context
=None):
756 member_line_obj
= self
.pool
.get('membership.membership_line')
757 print("DEV: [pos_membership] [pos_order_line] [create]: vals=%s context=%s" % (str(vals
), str(context
)))
758 res
= super(pos_order_line
, self
).create(cr
, uid
, vals
, context
=context
)
759 print ("DEV: [pos_membership] [pos_order_line] [create] [super] : res=%s" % str(res
))
760 line
= self
.browse(cr
, uid
, res
, context
=context
)
762 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
763 if line
.product_id
and line
.product_id
.membership
and not ml_ids
:
764 date_from
= line
.product_id
.membership_date_from
765 date_to
= line
.product_id
.membership_date_to
766 if line
.order_id
.date_order
> date_from
and line
.order_id
.date_order
< date_to
:
767 date_from
= line
.order_id
.date_order
768 if line
.product_id
.membership_date2date
:
769 date_from
= ('date_from' in context
770 and context
.get('date_from')
771 and datetime
.strptime(context
.get('date_from'), "%Y-%m-%d")
773 date_to
= date_from
+ relativedelta(days
= +364) # TODO: parameterize this delta?
774 date_from
= date_from
.strftime("%Y-%m-%d")
775 date_to
= date_to
.strftime("%Y-%m-%d")
776 print ("DEV: [pos_membership] [pos_order_line] [create] date_from: %s" % str(date_from
))
777 print ("DEV: [pos_membership] [pos_order_line] [create] date_to : %s" % str(date_to
))
778 member_line_obj
.create(cr
, uid
, {
779 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False,
780 'membership_id': line
.product_id
.id,
781 'member_price': line
.price_unit
,
782 'date': time
.strftime('%Y-%m-%d'),
783 'date_from': date_from
,
785 'pos_order_line': line
.id,
787 partners
= [line
.order_id
.partner_id
]
788 if line
.product_id
.membership_grouped
and line
.order_id
.partner_id
.associate_members
:
789 partners
.extend(line
.order_id
.partner_id
.associate_members
)
790 #Adding membership lines just for associate partners
791 for associate_member
in line
.order_id
.partner_id
.associate_members
:
792 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_from: %s" % str(date_from
))
793 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_to : %s" % str(date_to
))
794 member_line_obj
.create(cr
, uid
, {
795 'partner': associate_member
.id,
796 'membership_id': line
.product_id
.id,
797 'member_price': line
.price_unit
,
798 'date': time
.strftime('%Y-%m-%d'),
799 'date_from': date_from
,
801 'pos_order_line': line
.id,
803 elif line
.product_id
.membership_grouped
and not line
.order_id
.partner_id
.associate_members
:
804 raise osv
.except_osv(_('Error!!!'), _('You try to order grouped membership product to a partner who hasn\'t associated partners.'))
805 #Define member ident if it's necessary
808 print ("\033[7mXXX: [pos_membership] [pos_order_line] [create] : pos_order_line has no partner_id!\033[0m")
810 if not i
.member_ident
:
811 print ("DEV: [pos_membership] [pos_order_line] [create] [partners] : i=%s i.id=%s" % (str(i
), str(i
.id)))
812 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
813 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
814 print ("DEV: [pos_membership] [pos_order_line] [create] : return=%s" % str(res
))
819 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: