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 # POS Membership 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
31 ('none', 'Non Member'),
32 ('canceled', 'Cancelled Member'),
33 ('old', 'Old Member'),
34 ('waiting', 'Waiting Member'),
35 ('invoiced', 'Invoiced Member'),
36 ('free', 'Free Member'),
37 ('paid', 'Paid Member'),
41 class pos_session(osv
.osv
):
42 _inherit
= 'pos.session'
44 def open_cb(self
, cr
, uid
, ids
, context
=None):
46 Avoid call the Point Of Sale interface and set the pos.session to 'opened' (in progress)
51 if isinstance(ids
, (int, long)):
54 this_record
= self
.browse(cr
, uid
, ids
[0], context
=context
)
55 this_record
._workflow
_signal
('open')
57 context
.update(active_id
=this_record
.id)
65 class pos_order(osv
.osv
):
66 _inherit
= 'pos.order'
68 def create_partner_from_ui(self
, cr
, uid
, partners
, context
=None):
69 print ("DEV: [pos_membership] [create_partner_from_ui] partners=%s" % str(partners
))
71 partner_obj
= self
.pool
.get('res.partner')
72 for tmp_partner
in partners
:
73 partner
= tmp_partner
['data']
74 partner_id
= partner_obj
.create(cr
, uid
, {
75 'name': partner
['name'],
77 partner_ids
.append(partner_id
)
78 #self.signal_paid(cr, uid, [partner_id])
81 def create_from_ui(self
, cr
, uid
, orders
, context
=None):
82 # NOTE: copied from openerp/addons/point_of_sale/point_of_sale.py
83 #_logger.info("orders: %r", orders)
84 print ("DEV: [pos_membership] [create_from_ui] order=", str(orders
))
86 for tmp_order
in orders
:
87 order
= tmp_order
['data']
88 order_id
= self
.create(cr
, uid
, {
89 'name': order
['name'],
90 'user_id': order
['user_id'] or False,
91 'session_id': order
['pos_session_id'],
92 'lines': order
['lines'],
93 'pos_reference': order
['name'],
94 #-- BEGIN pos_membership
95 'partner_id': order
['partner_id'],
96 #-- END pos_membership
99 for payments
in order
['statement_ids']:
100 payment
= payments
[2]
101 self
.add_payment(cr
, uid
, order_id
, {
102 'amount': payment
['amount'] or 0.0,
103 'payment_date': payment
['name'],
104 'statement_id': payment
['statement_id'],
105 'payment_name': payment
.get('note', False),
106 'journal': payment
['journal_id']
109 if order
['amount_return']:
110 session
= self
.pool
.get('pos.session').browse(cr
, uid
, order
['pos_session_id'], context
=context
)
111 cash_journal
= session
.cash_journal_id
112 cash_statement
= False
114 cash_journal_ids
= filter(lambda st
: st
.journal_id
.type == 'cash', session
.statement_ids
)
115 if not len(cash_journal_ids
):
116 raise osv
.except_osv(_('error!'),
117 _("No cash statement found for this session. Unable to record returned cash."))
118 cash_journal
= cash_journal_ids
[0].journal_id
119 self
.add_payment(cr
, uid
, order_id
, {
120 'amount': -order
['amount_return'],
121 'payment_date': time
.strftime('%Y-%m-%d %H:%M:%S'),
122 'payment_name': _('return'),
123 'journal': cash_journal
.id,
125 order_ids
.append(order_id
)
126 wf_service
= netsvc
.LocalService("workflow")
127 wf_service
.trg_validate(uid
, 'pos.order', order_id
, 'paid', cr
)
133 class membership_line(osv
.osv
):
135 _inherit
= 'membership.membership_line'
137 def _get_partners(self
, cr
, uid
, ids
, context
=None):
138 list_membership_line
= []
139 member_line_obj
= self
.pool
.get('membership.membership_line')
140 for partner
in self
.pool
.get('res.partner').browse(cr
, uid
, ids
, context
=context
):
141 if partner
.member_lines
:
142 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('id', 'in', [l
.id for l
in partner
.member_lines
])], context
=context
)
143 print("DEV: [pos_membership] [membership_line] [_get_partners]: ids=%s res=%s" % (str(ids
), str(list_membership_line
)))
144 return list_membership_line
146 #def _get_membership_lines_from_account_invoice(self, cr, uid, ids, context=None):
147 # list_membership_line = []
148 # member_line_obj = self.pool.get('membership.membership_line')
149 # for invoice in self.pool.get('account.invoice').browse(cr, uid, ids, context=context):
150 # if invoice.invoice_line:
151 # list_membership_line += member_line_obj.search(cr, uid, [('account_invoice_line', 'in', [ l.id for l in invoice.invoice_line])], context=context)
153 # { 'class': 'account.invoice'
154 # , 'ids': list_membership_line
156 # #res= list_membership_line
157 # print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_account_invoice]: res=%s" % str(res))
159 def _get_membership_lines_from_pos_order(self
, cr
, uid
, ids
, context
=None):
160 list_membership_line
= []
161 member_line_obj
= self
.pool
.get('membership.membership_line')
162 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: ids=%s context=%s" % (str(ids
), str(context
)))
163 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
165 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('pos_order_line', 'in', [l
.id for l
in order
.lines
])], context
=context
)
167 # { 'class': 'pos.order'
168 # , 'ids': list_membership_line
170 res
= list_membership_line
171 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: res=%s" % str(res
))
174 def _check_membership_date(self
, cr
, uid
, ids
, context
=None):
175 """Check if membership product is not in the past
176 @param self: The object pointer
177 @param cr: the current row, from the database cursor,
178 @param uid: the current user’s ID for security checks,
179 @param ids: List of Membership Line IDs
180 @param context: A standard dictionary for contextual values
184 SELECT MIN(ml.date_to - ai.date_invoice)
185 FROM membership_membership_line ml
186 JOIN account_invoice_line ail ON (
187 ml.account_invoice_line = ail.id
189 JOIN account_invoice ai ON (
190 ai.id = ail.invoice_id)
191 WHERE ml.id IN %s''', (tuple(ids
),))
194 if r
[0] and r
[0] < 0:
197 SELECT MIN(ml.date_to - ai.date_order)
198 FROM membership_membership_line ml
199 JOIN pos_order_line ail ON (
200 ml.pos_order_line = ail.id
202 JOIN pos_order ai ON (
203 ai.id = ail.order_id)
204 WHERE ml.id IN %s''', (tuple(ids
),))
207 if r
[0] and r
[0] < 0:
211 def _state(self
, cr
, uid
, ids
, name
, args
, context
=None):
212 """Compute the state lines
213 @param self: The object pointer
214 @param cr: the current row, from the database cursor,
215 @param uid: the current user’s ID for security checks,
216 @param ids: List of Membership Line IDs
217 @param name: Field Name
218 @param context: A standard dictionary for contextual values
219 @param return: Dictionary of state Value
222 print("DEV: [pos_membership] [membership_line] [_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
223 inv_obj
= self
.pool
.get('account.invoice')
224 ord_obj
= self
.pool
.get('pos.order')
225 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
227 SELECT i.state, i.id FROM
231 SELECT l.invoice_id FROM
232 account_invoice_line l WHERE
234 SELECT ml.account_invoice_line FROM
235 membership_membership_line ml WHERE
240 fetched
= cr
.fetchone()
244 if (istate
== 'draft') |
(istate
== 'proforma'):
246 elif istate
== 'open':
248 elif istate
== 'paid':
250 inv
= inv_obj
.browse(cr
, uid
, fetched
[1], context
=context
)
251 for payment
in inv
.payment_ids
:
252 if payment
.invoice
and payment
.invoice
.type == 'out_refund':
254 elif istate
== 'cancel':
259 SELECT i.state, i.id FROM
263 SELECT l.order_id FROM
264 pos_order_line l WHERE
266 SELECT ml.pos_order_line FROM
267 membership_membership_line ml WHERE
272 fetched
= cr
.fetchone()
274 res
[line
.id] = 'canceled'
276 print("DEV: [pos_membership] [membership_line] [_state]: line.partner.id=%s" % (str(line
.partner
.id)))
277 self
.write(cr
, uid
, line
.id, {'partner': line
.partner
.id})
278 # NOTE: force une mise à jour du partner,
279 # car il n'y en a pas lors de la création du pos.order
280 # dans le PoS (pour le moment)
281 partner_obj
= self
.pool
.get('res.partner')
282 for partner
in partner_obj
.browse(cr
, uid
, [line
.partner
.id], context
=context
):
283 if not partner
.member_ident
:
284 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
285 partner_obj
.write(cr
, uid
, partner
.id, {'member_ident': mbr_id
})
288 if (ostate
== 'paid') |
(ostate
== 'draft'):
290 elif (ostate
== 'done') |
(ostate
== 'invoiced'):
292 # XXX: regarder l'équivalent de out_refund pour un pos.order
293 print("DEV: [pos_membership] [membership_line] [_state]: paid: TODO")
294 #inv = ord_obj.browse(cr, uid, fetched[1], context=context)
295 #for payment in inv.payment_ids:
296 # if payment.invoice and payment.invoice.type == 'out_refund':
298 elif ostate
== 'cancel':
301 print("DEV: [pos_membership] [membership_line] [_state]: return=%s" % (str(res
)))
304 def write(self
, cr
, uid
, ids
, vals
, context
=None):
305 print("DEV: [pos_membership] [membership_line] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
306 res
= super(membership_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
307 print("DEV: [pos_membership] [membership_line] [write]: res=%s" % str(res
))
310 def create(self
, cr
, uid
, vals
, context
=None):
311 print("DEV: [pos_membership] [membership_line] [create]: vals=%s" % (str(vals
)))
312 member_line_obj
= self
.pool
.get('membership.membership_line')
313 res
= super(membership_line
, self
).create(cr
, uid
, vals
, context
=context
)
314 print("DEV: [pos_membership] [membership_line] [create]: res=%s" % (str(res
)))
318 'pos_order_line': fields
.many2one('pos.order.line', 'POS Order line', readonly
=True),
319 'pos_order_id': fields
.related('pos_order_line', 'order_id', type='many2one', relation
='pos.order', string
='Order', readonly
=True),
320 'state': fields
.function(_state
,
321 string
='Membership Status', type='selection',
324 #'account.invoice': (_get_membership_lines_from_account_invoice, ['state'], 10),
325 # NOTE: déjà géré par membership.membership_line._get_membership_lines
326 'pos.order': (_get_membership_lines_from_pos_order
, ['state', 'partner_id'], 10),
327 'res.partner': (_get_partners
, ['membership_state'], 12),
328 }, help="""It indicates the membership status.
329 -Non Member: A member who has not applied for any membership.
330 -Cancelled Member: A member who has cancelled his membership.
331 -Old Member: A member whose membership date has expired.
332 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
333 -Invoiced Member: A member whose invoice has been created.
334 -Paid Member: A member who has paid the membership amount."""),
335 'company_id': fields
.related('account_invoice_line', 'invoice_id', 'company_id', type="many2one", relation
="res.company", string
="Company", readonly
=True, store
=True)
336 # XXX: pos_order_line a aussi un company_id
342 class Partner(osv
.osv
):
344 _inherit
= 'res.partner'
346 def _get_partner_id(self
, cr
, uid
, ids
, context
=None):
347 print("DEV: [pos_membership] [Partner] [_get_partner_id]: ids=%s context=%s" % (str(ids
), str(context
)))
348 member_line_obj
= self
.pool
.get('membership.membership_line')
349 res_obj
= self
.pool
.get('res.partner')
350 data_inv
= member_line_obj
.browse(cr
, uid
, ids
, context
=context
)
352 for data
in data_inv
:
353 list_partner
.append(data
.partner
.id)
356 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
358 print("DEV: [pos_membership] [Partner] [_get_partner_id]: res=%s" % (str(list_partner
)))
361 def _get_invoice_partner(self
, cr
, uid
, ids
, context
=None):
362 inv_obj
= self
.pool
.get('account.invoice')
363 res_obj
= self
.pool
.get('res.partner')
364 data_inv
= inv_obj
.browse(cr
, uid
, ids
, context
=context
)
366 for data
in data_inv
:
367 list_partner
.append(data
.partner_id
.id)
370 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
374 def _get_order_partner(self
, cr
, uid
, ids
, context
=None):
375 ord_obj
= self
.pool
.get('pos.order')
376 res_obj
= self
.pool
.get('res.partner')
377 data_ord
= ord_obj
.browse(cr
, uid
, ids
, context
=context
)
379 for data
in data_ord
:
380 list_partner
.append(data
.partner_id
.id)
383 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
387 def _membership_state(self
, cr
, uid
, ids
, name
, args
, context
=None):
388 """This Function return Membership State For Given Partner.
389 @param self: The object pointer
390 @param cr: the current row, from the database cursor,
391 @param uid: the current user’s ID for security checks,
392 @param ids: List of Partner IDs
393 @param name: Field Name
394 @param context: A standard dictionary for contextual values
395 @param return: Dictionary of Membership state Value
398 print("DEV: [pos_membership] [Partner] [_membership_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
401 today
= time
.strftime('%Y-%m-%d')
403 print("DEV: [pos_membership] [Partner] [_membership_state] id=%s" % (str(id)))
404 partner_data
= self
.browse(cr
, uid
, id, context
=context
)
405 if partner_data
.membership_cancel
and today
> partner_data
.membership_cancel
:
408 if partner_data
.membership_stop
and today
> partner_data
.membership_stop
:
412 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines] [test]")
413 if partner_data
.member_lines
:
414 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines]" % ())
415 for mline
in partner_data
.member_lines
:
416 print("DEV: [pos_membership] [Partner] [_membership_state] [mline]: id=%s" % str(mline
.id))
417 if mline
.date_to
>= today
:
418 if mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
:
419 istate
= mline
.account_invoice_line
.invoice_id
.state
420 print("DEV: [pos_membership] [Partner] [_membership_state] [account_invoice_line]: id=%s istate=%s" % (str(mline
.account_invoice_line
.invoice_id
.id), str(istate
)))
423 inv
= mline
.account_invoice_line
.invoice_id
424 for payment
in inv
.payment_ids
:
425 if payment
.invoice
.type == 'out_refund':
428 elif istate
== 'open' and s
!= 0:
430 elif istate
== 'cancel' and s
!= 0 and s
!= 1:
432 elif (istate
== 'draft' or istate
== 'proforma') and s
!= 0 and s
!= 1:
434 elif mline
.pos_order_line
and mline
.pos_order_line
.order_id
:
435 ostate
= mline
.pos_order_line
.order_id
.state
436 print("DEV: [pos_membership] [Partner] [_membership_state] [pos_order_line]: id=%s ostate=%s" % (str(mline
.pos_order_line
.order_id
.id), str(ostate
)))
437 if ostate
== 'paid' and s
!= 0 and s
!= 1:
439 if ostate
== 'invoiced':
443 # XXX: regarder l'équivalent de out_refund pour un pos.order
444 print("DEV: [pos_membership] [partner] [_membership_state]: paid: TODO")
445 #inv = mline.pos_order_line.order_id
446 #for payment in inv.payment_ids:
447 # if payment.invoice.type == 'out_refund':
450 elif ostate
== 'open' and s
!= 0:
451 # XXX: 1 donne invoiced, c'est pitet pas bon
452 print("DEV: [pos_membership] [partner] [_membership_state]: invoiced: TODO")
454 elif ostate
== 'cancel' and s
!= 0 and s
!= 1:
456 elif ostate
== 'draft' and s
!= 0 and s
!= 1:
459 for mline
in partner_data
.member_lines
:
460 if mline
.date_from
< today
and \
461 mline
.date_to
< today
and \
462 mline
.date_from
<= mline
.date_to
and \
463 ((mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
.state
) == 'paid' or \
464 (mline
.pos_order_line
and \
465 (mline
.pos_order_line
.order_id
.state
== 'paid' or \
466 mline
.pos_order_line
.order_id
.state
== 'done' or \
467 mline
.pos_order_line
.order_id
.state
== 'invoiced' ))):
483 if partner_data
.free_member
and s
!= 0:
485 if partner_data
.associate_member
:
486 res_state
= self
._membership
_state
(cr
, uid
, [partner_data
.associate_member
.id], name
, args
, context
=context
)
487 res
[id] = res_state
[partner_data
.associate_member
.id]
488 print("DEV: [pos_membership] [Partner] [_membership_state]: res=%s" % (str(res
)))
491 def _membership_date(self
, cr
, uid
, ids
, name
, args
, context
=None):
492 """Return date of membership"""
495 member_line_obj
= self
.pool
.get('membership.membership_line')
496 print("DEV: [pos_membership] [Partner] [_membership_date]: ids=%s" % (str(ids
)))
497 for partner
in self
.browse(cr
, uid
, ids
, context
=context
):
498 if partner
.associate_member
:
499 partner_id
= partner
.associate_member
.id
501 partner_id
= partner
.id
503 'membership_start': False,
504 'membership_stop': False,
505 'membership_cancel': False
507 if name
== 'membership_start':
508 line_id
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
509 limit
=1, order
='date_from', context
=context
)
511 res
[partner
.id]['membership_start'] = member_line_obj
.read(cr
, uid
, line_id
[0],
512 ['date_from'], context
=context
)['date_from']
513 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_start]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_start'])))
515 if name
== 'membership_stop':
516 line_id1
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
517 limit
=1, order
='date_to desc', context
=context
)
519 res
[partner
.id]['membership_stop'] = member_line_obj
.read(cr
, uid
, line_id1
[0],
520 ['date_to'], context
=context
)['date_to']
521 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_stop]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_stop'])))
523 if name
== 'membership_cancel':
524 if partner
.membership_state
== 'canceled':
525 line_id2
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner
.id)], limit
=1, order
='date_cancel', context
=context
)
527 res
[partner
.id]['membership_cancel'] = member_line_obj
.read(cr
, uid
, line_id2
[0], ['date_cancel'], context
=context
)['date_cancel']
528 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_cancel]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_cancel'])))
529 print("DEV: [pos_membership] [Partner] [_membership_date]: res=%s" % (str(res
)))
532 def _get_partners(self
, cr
, uid
, ids
, context
=None):
535 ids2
= self
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
539 def __get_membership_state(self
, *args
, **kwargs
):
540 return self
._membership
_state
(*args
, **kwargs
)
543 'membership_state': fields
.function(
544 __get_membership_state
,
545 string
= 'Current Membership Status', type = 'selection',
548 # NOTE: il est important que la priorité soit plus grande
549 # que les membership_{start,stop,cancel}
550 # car _membership_state s'en sert et doit donc les trouver à jour.
551 'account.invoice': (_get_invoice_partner
, ['state'], 20),
552 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 20),
553 'membership.membership_line': (_get_partner_id
, ['state'], 20),
554 'res.partner': (_get_partners
, ['free_member', 'membership_state', 'associate_member'], 20)
555 }, help="""It indicates the membership state.
556 -Non Member: A partner who has not applied for any membership.
557 -Cancelled Member: A member who has cancelled his membership.
558 -Old Member: A member whose membership date has expired.
559 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
560 -Invoiced Member: A member whose invoice has been created.
561 -Paying member: A member who has paid the membership fee."""),
562 'membership_start': fields
.function(
563 _membership_date
, multi
= 'membership_start',
564 string
= 'Membership Start Date', type = 'date',
566 'account.invoice': (_get_invoice_partner
, ['state'], 10),
567 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
568 'membership.membership_line': (_get_partner_id
, ['state'], 10),
569 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
570 }, help="Date from which membership becomes active."),
571 'membership_stop': fields
.function(
573 string
= 'Membership End Date', type='date', multi
='membership_stop',
575 'account.invoice': (_get_invoice_partner
, ['state'], 10),
576 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
577 'membership.membership_line': (_get_partner_id
, ['state'], 10),
578 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
579 }, help="Date until which membership remains active."),
580 'membership_cancel': fields
.function(
582 string
= 'Cancel Membership Date', type='date', multi
='membership_cancel',
584 'account.invoice': (_get_invoice_partner
, ['state'], 11),
585 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 11),
586 'membership.membership_line': (_get_partner_id
, ['state'], 10),
587 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
588 }, help="Date on which membership has been cancelled"),
593 class pos_order(osv
.osv
):
594 _inherit
= 'pos.order'
596 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py
597 def action_invoice(self
, cr
, uid
, ids
, context
=None):
598 print ("DEV: [pos_membership] [pos_order] [action_invoice]")
599 wf_service
= netsvc
.LocalService("workflow")
600 inv_ref
= self
.pool
.get('account.invoice')
601 inv_line_ref
= self
.pool
.get('account.invoice.line')
602 product_obj
= self
.pool
.get('product.product')
605 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
607 inv_ids
.append(order
.invoice_id
.id)
610 if not order
.partner_id
:
611 raise osv
.except_osv(_('Error!'), _('Please provide a partner for the sale.'))
613 acc
= order
.partner_id
.property_account_receivable
.id
614 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py to fix account.invoice.line creation
617 'origin': order
.name
,
619 'journal_id': order
.sale_journal
.id or None,
620 'type': 'out_invoice',
621 'reference': order
.name
,
622 'partner_id': order
.partner_id
.id,
623 'comment': order
.note
or '',
624 'currency_id': order
.pricelist_id
.currency_id
.id, # considering partner's sale pricelist's currency
627 inv
.update(inv_ref
.onchange_partner_id(cr
, uid
, [], 'out_invoice', order
.partner_id
.id)['value'])
628 if not inv
.get('account_id', None):
629 inv
['account_id'] = acc
630 for line
in order
.lines
:
632 #'invoice_id': inv_id,
633 'product_id': line
.product_id
.id,
634 'quantity': line
.qty
,
636 inv_name
= product_obj
.name_get(cr
, uid
, [line
.product_id
.id], context
=context
)[0][1]
637 inv_line
.update(inv_line_ref
.product_id_change(cr
, uid
, [],
639 line
.product_id
.uom_id
.id,
640 line
.qty
, partner_id
= order
.partner_id
.id,
641 fposition_id
=order
.partner_id
.property_account_position
.id)['value'])
642 if line
.product_id
.description_sale
:
643 inv_line
['note'] = line
.product_id
.description_sale
644 inv_line
['price_unit'] = line
.price_unit
645 inv_line
['discount'] = line
.discount
646 inv_line
['name'] = inv_name
647 inv_line
['invoice_line_tax_id'] = [(6, 0, [x
.id for x
in line
.product_id
.taxes_id
] )]
648 inv_line_ref
.create(cr
, uid
, inv_line
, context
=context
)
649 #inv_line_ref.create(cr, uid, inv_line, context=context)
650 inv
['invoice_line'].append((0, 0, inv_line
))
651 inv_id
= inv_ref
.create(cr
, uid
, inv
, context
=context
)
653 self
.write(cr
, uid
, [order
.id], {'invoice_id': inv_id
, 'state': 'invoiced'}, context
=context
)
654 inv_ref
.confirm_paid(cr
, uid
, [inv_id
], context
=context
)
655 inv_ids
.append(inv_id
)
656 inv_ref
.button_reset_taxes(cr
, uid
, [inv_id
], context
=context
)
657 wf_service
.trg_validate(uid
, 'pos.order', order
.id, 'invoice', cr
)
659 if not inv_ids
: return {}
661 mod_obj
= self
.pool
.get('ir.model.data')
662 res
= mod_obj
.get_object_reference(cr
, uid
, 'account', 'invoice_form')
663 res_id
= res
and res
[1] or False
665 'name': _('Customer Invoice'),
669 'res_model': 'account.invoice',
670 'context': "{'type':'out_invoice'}",
671 'type': 'ir.actions.act_window',
674 'res_id': inv_ids
and inv_ids
[0] or False,
677 def write(self
, cr
, uid
, ids
, vals
, context
=None):
678 print("DEV: [pos_membership] [pos_order] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
679 pos_order_obj
= self
.pool
.get('pos.order')
680 res
= super(pos_order
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
681 print("DEV: [pos_membership] [pos_order] [write]: res=%s" % str(res
))
684 def create(self
, cr
, uid
, vals
, context
=None):
685 print("DEV: [pos_membership] [pos_order] [create]: vals=%s" % (str(vals
)))
686 pos_order_obj
= self
.pool
.get('pos.order')
687 res
= super(pos_order
, self
).create(cr
, uid
, vals
, context
=context
)
688 print("DEV: [pos_membership] [pos_order] [create]: res=%s" % (str(res
)))
691 def onchange_partner_id(self
, cr
, uid
, ids
, part
=False, context
=None):
694 res
= super(pos_order
, self
).onchange_partner_id(cr
, uid
, ids
, part
=part
, context
=context
)
695 membership_stop
= self
.pool
.get('res.partner').browse(cr
, uid
, part
, context
=context
).membership_stop
696 res
['value']['membership_stop'] = membership_stop
699 def _get_membership_stop(self
, cr
, uid
, ids
, name
, args
, context
=None):
700 """This function return the end date of the partner in pos order."""
702 for order
in self
.browse(cr
, uid
, ids
):
703 res
[order
.id] = order
.partner_id
.membership_stop
707 'membership_stop': fields
.function(
708 _get_membership_stop
,
709 string
='Membership stop',
711 help='The end date of the last membership of this partner.',
716 class pos_order_line(osv
.osv
):
717 _inherit
= 'pos.order.line'
719 def write(self
, cr
, uid
, ids
, vals
, context
=None):
720 print("DEV: [pos_membership] [pos_order_line] [write]: ids=%s vals=%s context=%s" % (str(ids
), str(vals
), str(context
)))
721 member_line_obj
= self
.pool
.get('membership.membership_line')
722 res
= super(pos_order_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
723 print ("DEV: [pos_membership] [pos_order_line] [write] [super] : res=%s" % str(res
))
724 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
725 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
726 if line
.product_id
and line
.product_id
.membership
:
727 member_line_id
= member_line_obj
.search(cr
, uid
728 , [('partner', '=', line
.order_id
.partner_id
.id)
729 ,('pos_order_line', '=', line
.id)]
732 for member_line
in member_line_obj
.browse(cr
, uid
, member_line_id
, context
=context
):
733 # NOTE: get member_line created in pos_membership.pos_order_line.create
734 date_from
= member_line
.date_from
735 date_to
= member_line
.date_to
736 if line
.product_id
.membership_date2date
:
737 date_from
= ('date_from' in context
738 and context
.get('date_from')
739 and datetime
.strptime(context('date_from'), "%Y-%m-%d")
741 date_to
= date_from
+ relativedelta(months
= +12) # TODO: parameterize this delta?
742 date_from
= date_from
.strftime("%Y-%m-%d")
743 date_to
= date_to
.strftime("%Y-%m-%d")
744 print ("DEV: [pos_membership] [pos_order_line] [write] date_from: %s" % str(date_from
))
745 print ("DEV: [pos_membership] [pos_order_line] [write] date_to : %s" % str(date_to
))
746 member_line_obj
.write(cr
, uid
, member_line
.id
747 , {'date_from': date_from
751 if line
.product_id
.membership_grouped
:
752 if line
.order_id
.partner_id
.associate_members
:
753 associate_member_line_ids
= member_line_obj
.search(cr
, uid
754 , [ ('pos_order_line', '=', line
.id)
755 , ('partner', '!=', line
.order_id
.partner_id
.id)
758 for associate_member_line
in member_line_obj
.browse(cr
, uid
, associate_member_line_ids
, context
=context
):
759 print ("DEV: [pos_membership] [pos_order_line] [write] [associate] date_from: %s" % str(date_from
))
760 print ("DEV: [pos_membership] [pos_order_line] [write] [associate] date_to : %s" % str(date_to
))
761 member_line_obj
.write(cr
, uid
, associate_member_line
.id
762 , {'date_from': date_from
767 print("DEV: mettre une contrainte pour l'objet\
768 membership.membership_line interdisant les\
769 adhésions groupées reliées à des partenaires\
770 sans membres associés")
772 associate_member_line_ids
= member_line_obj
.search(cr
, uid
773 , [ ('pos_order_line', '=', line
.id)
774 , ('partner', '!=', line
.order_id
.partner_id
.id)
777 member_line_obj
.unlink(cr
, uid
, associate_member_line_ids
, context
=context
)
778 #Define member ident if it's necessary
779 partners
= [line
.order_id
.partner_id
]
780 if line
.order_id
.partner_id
.associate_members
:
781 partners
.extend(line
.order_id
.partner_id
.associate_members
)
783 if not i
.member_ident
:
784 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
785 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
786 if line
.product_id
and not line
.product_id
.membership
and ml_ids
:
787 # Product line has changed to a non membership product
788 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
789 print ("DEV: [pos_membership] [pos_order_line] [write] : return=%s" % str(res
))
792 def unlink(self
, cr
, uid
, ids
, context
=None):
793 """Remove Membership Line Record for Account Invoice Line
795 member_line_obj
= self
.pool
.get('membership.membership_line')
797 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', id)], context
=context
)
798 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
799 return super(pos_order_line
, self
).unlink(cr
, uid
, ids
, context
=context
)
801 def create(self
, cr
, uid
, vals
, context
=None):
802 member_line_obj
= self
.pool
.get('membership.membership_line')
803 print("DEV: [pos_membership] [pos_order_line] [create]: vals=%s context=%s" % (str(vals
), str(context
)))
804 res
= super(pos_order_line
, self
).create(cr
, uid
, vals
, context
=context
)
805 print ("DEV: [pos_membership] [pos_order_line] [create] [super] : res=%s" % str(res
))
806 line
= self
.browse(cr
, uid
, res
, context
=context
)
808 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
809 if line
.product_id
and line
.product_id
.membership
and not ml_ids
:
810 date_from
= line
.product_id
.membership_date_from
811 date_to
= line
.product_id
.membership_date_to
812 if line
.order_id
.date_order
> date_from
and line
.order_id
.date_order
< date_to
:
813 date_from
= line
.order_id
.date_order
814 if line
.product_id
.membership_date2date
:
815 date_from
= ('date_from' in context
816 and context
.get('date_from')
817 and datetime
.strptime(context
.get('date_from'), "%Y-%m-%d")
819 date_to
= date_from
+ relativedelta(days
= +364) # TODO: parameterize this delta?
820 date_from
= date_from
.strftime("%Y-%m-%d")
821 date_to
= date_to
.strftime("%Y-%m-%d")
822 print ("DEV: [pos_membership] [pos_order_line] [create] date_from: %s" % str(date_from
))
823 print ("DEV: [pos_membership] [pos_order_line] [create] date_to : %s" % str(date_to
))
824 member_line_obj
.create(cr
, uid
, {
825 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False,
826 'membership_id': line
.product_id
.id,
827 'member_price': line
.price_unit
,
828 'date': time
.strftime('%Y-%m-%d'),
829 'date_from': date_from
,
831 'pos_order_line': line
.id,
833 partners
= [line
.order_id
.partner_id
]
834 if line
.product_id
.membership_grouped
and line
.order_id
.partner_id
.associate_members
:
835 partners
.extend(line
.order_id
.partner_id
.associate_members
)
836 #Adding membership lines just for associate partners
837 for associate_member
in line
.order_id
.partner_id
.associate_members
:
838 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_from: %s" % str(date_from
))
839 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_to : %s" % str(date_to
))
840 member_line_obj
.create(cr
, uid
, {
841 'partner': associate_member
.id,
842 'membership_id': line
.product_id
.id,
843 'member_price': line
.price_unit
,
844 'date': time
.strftime('%Y-%m-%d'),
845 'date_from': date_from
,
847 'pos_order_line': line
.id,
849 elif line
.product_id
.membership_grouped
and not line
.order_id
.partner_id
.associate_members
:
850 raise osv
.except_osv(_('Error!!!'), _('You try to order grouped membership product to a partner who hasn\'t associated partners.'))
851 #Define member ident if it's necessary
854 print ("\033[7mXXX: [pos_membership] [pos_order_line] [create] : pos_order_line has no partner_id!\033[0m")
856 if not i
.member_ident
:
857 print ("DEV: [pos_membership] [pos_order_line] [create] [partners] : i=%s i.id=%s" % (str(i
), str(i
.id)))
858 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
859 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
860 print ("DEV: [pos_membership] [pos_order_line] [create] : return=%s" % str(res
))
865 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: