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'),
42 class pos_order(osv
.osv
):
43 _inherit
= 'pos.order'
45 def create_partner_from_ui(self
, cr
, uid
, partners
, context
=None):
46 print ("DEV: [pos_membership] [create_partner_from_ui] partners=%s" % str(partners
))
48 partner_obj
= self
.pool
.get('res.partner')
49 for tmp_partner
in partners
:
50 partner
= tmp_partner
['data']
51 partner_id
= partner_obj
.create(cr
, uid
, {
52 'name': partner
['name'],
54 partner_ids
.append(partner_id
)
55 #self.signal_paid(cr, uid, [partner_id])
58 def create_from_ui(self
, cr
, uid
, orders
, context
=None):
59 # NOTE: copied from openerp/addons/point_of_sale/point_of_sale.py
60 #_logger.info("orders: %r", orders)
61 print ("DEV: [pos_membership] [create_from_ui] order=", str(orders
))
63 for tmp_order
in orders
:
64 order
= tmp_order
['data']
65 order_id
= self
.create(cr
, uid
, {
66 'name': order
['name'],
67 'user_id': order
['user_id'] or False,
68 'session_id': order
['pos_session_id'],
69 'lines': order
['lines'],
70 'pos_reference': order
['name'],
71 #-- BEGIN pos_membership
72 'partner_id': order
['partner_id'],
73 #-- END pos_membership
76 for payments
in order
['statement_ids']:
78 self
.add_payment(cr
, uid
, order_id
, {
79 'amount': payment
['amount'] or 0.0,
80 'payment_date': payment
['name'],
81 'statement_id': payment
['statement_id'],
82 'payment_name': payment
.get('note', False),
83 'journal': payment
['journal_id']
86 if order
['amount_return']:
87 session
= self
.pool
.get('pos.session').browse(cr
, uid
, order
['pos_session_id'], context
=context
)
88 cash_journal
= session
.cash_journal_id
89 cash_statement
= False
91 cash_journal_ids
= filter(lambda st
: st
.journal_id
.type == 'cash', session
.statement_ids
)
92 if not len(cash_journal_ids
):
93 raise osv
.except_osv(_('error!'),
94 _("No cash statement found for this session. Unable to record returned cash."))
95 cash_journal
= cash_journal_ids
[0].journal_id
96 self
.add_payment(cr
, uid
, order_id
, {
97 'amount': -order
['amount_return'],
98 'payment_date': time
.strftime('%Y-%m-%d %H:%M:%S'),
99 'payment_name': _('return'),
100 'journal': cash_journal
.id,
102 order_ids
.append(order_id
)
103 wf_service
= netsvc
.LocalService("workflow")
104 wf_service
.trg_validate(uid
, 'pos.order', order_id
, 'paid', cr
)
110 class membership_line(osv
.osv
):
112 _inherit
= 'membership.membership_line'
114 def _get_partners(self
, cr
, uid
, ids
, context
=None):
115 list_membership_line
= []
116 member_line_obj
= self
.pool
.get('membership.membership_line')
117 for partner
in self
.pool
.get('res.partner').browse(cr
, uid
, ids
, context
=context
):
118 if partner
.member_lines
:
119 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('id', 'in', [l
.id for l
in partner
.member_lines
])], context
=context
)
120 print("DEV: [pos_membership] [membership_line] [_get_partners]: ids=%s res=%s" % (str(ids
), str(list_membership_line
)))
121 return list_membership_line
123 #def _get_membership_lines_from_account_invoice(self, cr, uid, ids, context=None):
124 # list_membership_line = []
125 # member_line_obj = self.pool.get('membership.membership_line')
126 # for invoice in self.pool.get('account.invoice').browse(cr, uid, ids, context=context):
127 # if invoice.invoice_line:
128 # list_membership_line += member_line_obj.search(cr, uid, [('account_invoice_line', 'in', [ l.id for l in invoice.invoice_line])], context=context)
130 # { 'class': 'account.invoice'
131 # , 'ids': list_membership_line
133 # #res= list_membership_line
134 # print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_account_invoice]: res=%s" % str(res))
136 def _get_membership_lines_from_pos_order(self
, cr
, uid
, ids
, context
=None):
137 list_membership_line
= []
138 member_line_obj
= self
.pool
.get('membership.membership_line')
139 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: ids=%s context=%s" % (str(ids
), str(context
)))
140 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
142 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('pos_order_line', 'in', [l
.id for l
in order
.lines
])], context
=context
)
144 # { 'class': 'pos.order'
145 # , 'ids': list_membership_line
147 res
= list_membership_line
148 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: res=%s" % str(res
))
151 def _check_membership_date(self
, cr
, uid
, ids
, context
=None):
152 """Check if membership product is not in the past
153 @param self: The object pointer
154 @param cr: the current row, from the database cursor,
155 @param uid: the current user’s ID for security checks,
156 @param ids: List of Membership Line IDs
157 @param context: A standard dictionary for contextual values
161 SELECT MIN(ml.date_to - ai.date_invoice)
162 FROM membership_membership_line ml
163 JOIN account_invoice_line ail ON (
164 ml.account_invoice_line = ail.id
166 JOIN account_invoice ai ON (
167 ai.id = ail.invoice_id)
168 WHERE ml.id IN %s''', (tuple(ids
),))
171 if r
[0] and r
[0] < 0:
174 SELECT MIN(ml.date_to - ai.date_order)
175 FROM membership_membership_line ml
176 JOIN pos_order_line ail ON (
177 ml.pos_order_line = ail.id
179 JOIN pos_order ai ON (
180 ai.id = ail.order_id)
181 WHERE ml.id IN %s''', (tuple(ids
),))
184 if r
[0] and r
[0] < 0:
188 def _state(self
, cr
, uid
, ids
, name
, args
, context
=None):
189 """Compute the state lines
190 @param self: The object pointer
191 @param cr: the current row, from the database cursor,
192 @param uid: the current user’s ID for security checks,
193 @param ids: List of Membership Line IDs
194 @param name: Field Name
195 @param context: A standard dictionary for contextual values
196 @param return: Dictionary of state Value
199 print("DEV: [pos_membership] [membership_line] [_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
200 inv_obj
= self
.pool
.get('account.invoice')
201 ord_obj
= self
.pool
.get('pos.order')
202 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
204 SELECT i.state, i.id FROM
208 SELECT l.invoice_id FROM
209 account_invoice_line l WHERE
211 SELECT ml.account_invoice_line FROM
212 membership_membership_line ml WHERE
217 fetched
= cr
.fetchone()
221 if (istate
== 'draft') |
(istate
== 'proforma'):
223 elif istate
== 'open':
225 elif istate
== 'paid':
227 inv
= inv_obj
.browse(cr
, uid
, fetched
[1], context
=context
)
228 for payment
in inv
.payment_ids
:
229 if payment
.invoice
and payment
.invoice
.type == 'out_refund':
231 elif istate
== 'cancel':
236 SELECT i.state, i.id, i.partner_id FROM
240 SELECT l.order_id FROM
241 pos_order_line l WHERE
243 SELECT ml.pos_order_line FROM
244 membership_membership_line ml WHERE
249 fetched
= cr
.fetchone()
251 res
[line
.id] = 'canceled'
253 partner_id
= fetched
[2]
254 self
.write(cr
, uid
, line
.id, {'partner': partner_id
})
255 # NOTE: force une mise à jour du partner,
256 # car il n'y en a pas lors de la création du pos.order
257 # dans le PoS (pour le moment)
258 partner_obj
= self
.pool
.get('res.partner')
259 for partner
in partner_obj
.browse(cr
, uid
, [partner_id
], context
=context
):
260 if not partner
.member_ident
:
261 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
262 partner_obj
.write(cr
, uid
, partner
.id, {'member_ident': mbr_id
})
265 if (ostate
== 'paid') |
(ostate
== 'draft'):
267 elif (ostate
== 'done') |
(ostate
== 'invoiced'):
269 # XXX: regarder l'équivalent de out_refund pour un pos.order
270 print("DEV: [pos_membership] [membership_line] [_state]: paid: TODO")
271 #inv = ord_obj.browse(cr, uid, fetched[1], context=context)
272 #for payment in inv.payment_ids:
273 # if payment.invoice and payment.invoice.type == 'out_refund':
275 elif ostate
== 'cancel':
278 print("DEV: [pos_membership] [membership_line] [_state]: return=%s" % (str(res
)))
281 def write(self
, cr
, uid
, ids
, vals
, context
=None):
282 print("DEV: [pos_membership] [membership_line] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
283 member_line_obj
= self
.pool
.get('membership.membership_line')
284 res
= super(membership_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
285 print("DEV: [pos_membership] [membership_line] [write]: res=%s" % str(res
))
288 def create(self
, cr
, uid
, vals
, context
=None):
289 print("DEV: [pos_membership] [membership_line] [create]: vals=%s" % (str(vals
)))
290 member_line_obj
= self
.pool
.get('membership.membership_line')
291 res
= super(membership_line
, self
).create(cr
, uid
, vals
, context
=context
)
292 print("DEV: [pos_membership] [membership_line] [create]: res=%s" % (str(res
)))
296 'pos_order_line': fields
.many2one('pos.order.line', 'POS Order line', readonly
=True),
297 'pos_order_id': fields
.related('pos_order_line', 'order_id', type='many2one', relation
='pos.order', string
='Order', readonly
=True),
298 'state': fields
.function(_state
,
299 string
='Membership Status', type='selection',
302 #'account.invoice': (_get_membership_lines_from_account_invoice, ['state'], 10),
303 # NOTE: déjà géré par membership.membership_line._get_membership_lines
304 'pos.order': (_get_membership_lines_from_pos_order
, ['state', 'partner_id'], 10),
305 'res.partner': (_get_partners
, ['membership_state'], 12),
306 }, help="""It indicates the membership status.
307 -Non Member: A member who has not applied for any membership.
308 -Cancelled Member: A member who has cancelled his membership.
309 -Old Member: A member whose membership date has expired.
310 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
311 -Invoiced Member: A member whose invoice has been created.
312 -Paid Member: A member who has paid the membership amount."""),
313 'company_id': fields
.related('account_invoice_line', 'invoice_id', 'company_id', type="many2one", relation
="res.company", string
="Company", readonly
=True, store
=True)
314 # XXX: pos_order_line a aussi un company_id
320 class Partner(osv
.osv
):
322 _inherit
= 'res.partner'
324 def _get_partner_id(self
, cr
, uid
, ids
, context
=None):
325 print("DEV: [pos_membership] [Partner] [_get_partner_id]: ids=%s context=%s" % (str(ids
), str(context
)))
326 member_line_obj
= self
.pool
.get('membership.membership_line')
327 res_obj
= self
.pool
.get('res.partner')
328 data_inv
= member_line_obj
.browse(cr
, uid
, ids
, context
=context
)
330 for data
in data_inv
:
331 list_partner
.append(data
.partner
.id)
334 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
336 print("DEV: [pos_membership] [Partner] [_get_partner_id]: res=%s" % (str(list_partner
)))
339 def _get_invoice_partner(self
, cr
, uid
, ids
, context
=None):
340 inv_obj
= self
.pool
.get('account.invoice')
341 res_obj
= self
.pool
.get('res.partner')
342 data_inv
= inv_obj
.browse(cr
, uid
, ids
, context
=context
)
344 for data
in data_inv
:
345 list_partner
.append(data
.partner_id
.id)
348 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
352 def _get_order_partner(self
, cr
, uid
, ids
, context
=None):
353 ord_obj
= self
.pool
.get('pos.order')
354 res_obj
= self
.pool
.get('res.partner')
355 data_ord
= ord_obj
.browse(cr
, uid
, ids
, context
=context
)
357 for data
in data_ord
:
358 list_partner
.append(data
.partner_id
.id)
361 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
365 def _membership_state(self
, cr
, uid
, ids
, name
, args
, context
=None):
366 """This Function return Membership State For Given Partner.
367 @param self: The object pointer
368 @param cr: the current row, from the database cursor,
369 @param uid: the current user’s ID for security checks,
370 @param ids: List of Partner IDs
371 @param name: Field Name
372 @param context: A standard dictionary for contextual values
373 @param return: Dictionary of Membership state Value
376 print("DEV: [pos_membership] [Partner] [_membership_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
379 today
= time
.strftime('%Y-%m-%d')
381 print("DEV: [pos_membership] [Partner] [_membership_state] id=%s" % (str(id)))
382 partner_data
= self
.browse(cr
, uid
, id, context
=context
)
383 if partner_data
.membership_cancel
and today
> partner_data
.membership_cancel
:
386 if partner_data
.membership_stop
and today
> partner_data
.membership_stop
:
390 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines] [test]")
391 if partner_data
.member_lines
:
392 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines]" % ())
393 for mline
in partner_data
.member_lines
:
394 print("DEV: [pos_membership] [Partner] [_membership_state] [mline]: id=%s" % str(mline
.id))
395 if mline
.date_to
>= today
:
396 if mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
:
397 istate
= mline
.account_invoice_line
.invoice_id
.state
398 print("DEV: [pos_membership] [Partner] [_membership_state] [account_invoice_line]: id=%s istate=%s" % (str(mline
.account_invoice_line
.invoice_id
.id), str(istate
)))
401 inv
= mline
.account_invoice_line
.invoice_id
402 for payment
in inv
.payment_ids
:
403 if payment
.invoice
.type == 'out_refund':
406 elif istate
== 'open' and s
!= 0:
408 elif istate
== 'cancel' and s
!= 0 and s
!= 1:
410 elif (istate
== 'draft' or istate
== 'proforma') and s
!= 0 and s
!= 1:
412 elif mline
.pos_order_line
and mline
.pos_order_line
.order_id
:
413 ostate
= mline
.pos_order_line
.order_id
.state
414 print("DEV: [pos_membership] [Partner] [_membership_state] [pos_order_line]: id=%s ostate=%s" % (str(mline
.pos_order_line
.order_id
.id), str(ostate
)))
415 if ostate
== 'paid' and s
!= 0 and s
!= 1:
417 if ostate
== 'invoiced':
421 # XXX: regarder l'équivalent de out_refund pour un pos.order
422 print("DEV: [pos_membership] [partner] [_membership_state]: paid: TODO")
423 #inv = mline.pos_order_line.order_id
424 #for payment in inv.payment_ids:
425 # if payment.invoice.type == 'out_refund':
428 elif ostate
== 'open' and s
!= 0:
429 # XXX: 1 donne invoiced, c'est pitet pas bon
430 print("DEV: [pos_membership] [partner] [_membership_state]: invoiced: TODO")
432 elif ostate
== 'cancel' and s
!= 0 and s
!= 1:
434 elif ostate
== 'draft' and s
!= 0 and s
!= 1:
437 for mline
in partner_data
.member_lines
:
438 if mline
.date_from
< today
and \
439 mline
.date_to
< today
and \
440 mline
.date_from
<= mline
.date_to
and \
441 ((mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
.state
) == 'paid' or \
442 (mline
.pos_order_line
and \
443 (mline
.pos_order_line
.order_id
.state
== 'paid' or \
444 mline
.pos_order_line
.order_id
.state
== 'done' or \
445 mline
.pos_order_line
.order_id
.state
== 'invoiced' ))):
461 if partner_data
.free_member
and s
!= 0:
463 if partner_data
.associate_member
:
464 res_state
= self
._membership
_state
(cr
, uid
, [partner_data
.associate_member
.id], name
, args
, context
=context
)
465 res
[id] = res_state
[partner_data
.associate_member
.id]
466 print("DEV: [pos_membership] [Partner] [_membership_state]: res=%s" % (str(res
)))
469 def _membership_date(self
, cr
, uid
, ids
, name
, args
, context
=None):
470 """Return date of membership"""
473 member_line_obj
= self
.pool
.get('membership.membership_line')
474 print("DEV: [pos_membership] [Partner] [_membership_date]: ids=%s" % (str(ids
)))
475 for partner
in self
.browse(cr
, uid
, ids
, context
=context
):
476 if partner
.associate_member
:
477 partner_id
= partner
.associate_member
.id
479 partner_id
= partner
.id
481 'membership_start': False,
482 'membership_stop': False,
483 'membership_cancel': False
485 if name
== 'membership_start':
486 line_id
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
487 limit
=1, order
='date_from', context
=context
)
489 res
[partner
.id]['membership_start'] = member_line_obj
.read(cr
, uid
, line_id
[0],
490 ['date_from'], context
=context
)['date_from']
491 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_start]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_start'])))
493 if name
== 'membership_stop':
494 line_id1
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
495 limit
=1, order
='date_to desc', context
=context
)
497 res
[partner
.id]['membership_stop'] = member_line_obj
.read(cr
, uid
, line_id1
[0],
498 ['date_to'], context
=context
)['date_to']
499 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_stop]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_stop'])))
501 if name
== 'membership_cancel':
502 if partner
.membership_state
== 'canceled':
503 line_id2
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner
.id)], limit
=1, order
='date_cancel', context
=context
)
505 res
[partner
.id]['membership_cancel'] = member_line_obj
.read(cr
, uid
, line_id2
[0], ['date_cancel'], context
=context
)['date_cancel']
506 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_cancel]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_cancel'])))
507 print("DEV: [pos_membership] [Partner] [_membership_date]: res=%s" % (str(res
)))
510 def _get_partners(self
, cr
, uid
, ids
, context
=None):
513 ids2
= self
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
517 def __get_membership_state(self
, *args
, **kwargs
):
518 return self
._membership
_state
(*args
, **kwargs
)
521 'membership_state': fields
.function(
522 __get_membership_state
,
523 string
= 'Current Membership Status', type = 'selection',
526 # NOTE: il est important que la priorité soit plus grande
527 # que les membership_{start,stop,cancel}
528 # car _membership_state s'en sert et doit donc les trouver à jour.
529 'account.invoice': (_get_invoice_partner
, ['state'], 20),
530 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 20),
531 'membership.membership_line': (_get_partner_id
, ['state'], 20),
532 'res.partner': (_get_partners
, ['free_member', 'membership_state', 'associate_member'], 20)
533 }, help="""It indicates the membership state.
534 -Non Member: A partner who has not applied for any membership.
535 -Cancelled Member: A member who has cancelled his membership.
536 -Old Member: A member whose membership date has expired.
537 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
538 -Invoiced Member: A member whose invoice has been created.
539 -Paying member: A member who has paid the membership fee."""),
540 'membership_start': fields
.function(
541 _membership_date
, multi
= 'membership_start',
542 string
= 'Membership Start Date', type = 'date',
544 'account.invoice': (_get_invoice_partner
, ['state'], 10),
545 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
546 'membership.membership_line': (_get_partner_id
, ['state'], 10),
547 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
548 }, help="Date from which membership becomes active."),
549 'membership_stop': fields
.function(
551 string
= 'Membership End Date', type='date', multi
='membership_stop',
553 'account.invoice': (_get_invoice_partner
, ['state'], 10),
554 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
555 'membership.membership_line': (_get_partner_id
, ['state'], 10),
556 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
557 }, help="Date until which membership remains active."),
558 'membership_cancel': fields
.function(
560 string
= 'Cancel Membership Date', type='date', multi
='membership_cancel',
562 'account.invoice': (_get_invoice_partner
, ['state'], 11),
563 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 11),
564 'membership.membership_line': (_get_partner_id
, ['state'], 10),
565 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
566 }, help="Date on which membership has been cancelled"),
571 class pos_order(osv
.osv
):
572 _inherit
= 'pos.order'
574 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py
575 def action_invoice(self
, cr
, uid
, ids
, context
=None):
576 print ("DEV: [pos_membership] [pos_order] [action_invoice]")
577 wf_service
= netsvc
.LocalService("workflow")
578 inv_ref
= self
.pool
.get('account.invoice')
579 inv_line_ref
= self
.pool
.get('account.invoice.line')
580 product_obj
= self
.pool
.get('product.product')
583 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
585 inv_ids
.append(order
.invoice_id
.id)
588 if not order
.partner_id
:
589 raise osv
.except_osv(_('Error!'), _('Please provide a partner for the sale.'))
591 acc
= order
.partner_id
.property_account_receivable
.id
592 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py to fix account.invoice.line creation
595 'origin': order
.name
,
597 'journal_id': order
.sale_journal
.id or None,
598 'type': 'out_invoice',
599 'reference': order
.name
,
600 'partner_id': order
.partner_id
.id,
601 'comment': order
.note
or '',
602 'currency_id': order
.pricelist_id
.currency_id
.id, # considering partner's sale pricelist's currency
605 inv
.update(inv_ref
.onchange_partner_id(cr
, uid
, [], 'out_invoice', order
.partner_id
.id)['value'])
606 if not inv
.get('account_id', None):
607 inv
['account_id'] = acc
608 for line
in order
.lines
:
610 #'invoice_id': inv_id,
611 'product_id': line
.product_id
.id,
612 'quantity': line
.qty
,
614 inv_name
= product_obj
.name_get(cr
, uid
, [line
.product_id
.id], context
=context
)[0][1]
615 inv_line
.update(inv_line_ref
.product_id_change(cr
, uid
, [],
617 line
.product_id
.uom_id
.id,
618 line
.qty
, partner_id
= order
.partner_id
.id,
619 fposition_id
=order
.partner_id
.property_account_position
.id)['value'])
620 if line
.product_id
.description_sale
:
621 inv_line
['note'] = line
.product_id
.description_sale
622 inv_line
['price_unit'] = line
.price_unit
623 inv_line
['discount'] = line
.discount
624 inv_line
['name'] = inv_name
625 inv_line
['invoice_line_tax_id'] = ('invoice_line_tax_id' in inv_line
)\
626 and [(6, 0, inv_line
['invoice_line_tax_id'])] or []
627 #inv_line_ref.create(cr, uid, inv_line, context=context)
628 inv
['invoice_line'].append((0, 0, inv_line
))
629 inv_id
= inv_ref
.create(cr
, uid
, inv
, context
=context
)
631 self
.write(cr
, uid
, [order
.id], {'invoice_id': inv_id
, 'state': 'invoiced'}, context
=context
)
632 inv_ref
.confirm_paid(cr
, uid
, [inv_id
], context
=context
)
633 inv_ids
.append(inv_id
)
634 inv_ref
.button_reset_taxes(cr
, uid
, [inv_id
], context
=context
)
635 wf_service
.trg_validate(uid
, 'pos.order', order
.id, 'invoice', cr
)
637 if not inv_ids
: return {}
639 mod_obj
= self
.pool
.get('ir.model.data')
640 res
= mod_obj
.get_object_reference(cr
, uid
, 'account', 'invoice_form')
641 res_id
= res
and res
[1] or False
643 'name': _('Customer Invoice'),
647 'res_model': 'account.invoice',
648 'context': "{'type':'out_invoice'}",
649 'type': 'ir.actions.act_window',
652 'res_id': inv_ids
and inv_ids
[0] or False,
655 def write(self
, cr
, uid
, ids
, vals
, context
=None):
656 print("DEV: [pos_membership] [pos_order] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
657 pos_order_obj
= self
.pool
.get('pos.order')
658 res
= super(pos_order
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
659 print("DEV: [pos_membership] [pos_order] [write]: res=%s" % str(res
))
662 def create(self
, cr
, uid
, vals
, context
=None):
663 print("DEV: [pos_membership] [pos_order] [create]: vals=%s" % (str(vals
)))
664 pos_order_obj
= self
.pool
.get('pos.order')
665 res
= super(pos_order
, self
).create(cr
, uid
, vals
, context
=context
)
666 print("DEV: [pos_membership] [pos_order] [create]: res=%s" % (str(res
)))
671 class pos_order_line(osv
.osv
):
672 _inherit
= 'pos.order.line'
674 def write(self
, cr
, uid
, ids
, vals
, context
=None):
675 print("DEV: [pos_membership] [pos_order_line] [write]: ids=%s vals=%s context=%s" % (str(ids
), str(vals
), str(context
)))
676 member_line_obj
= self
.pool
.get('membership.membership_line')
677 res
= super(pos_order_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
678 print ("DEV: [pos_membership] [pos_order_line] [write] [super] : res=%s" % str(res
))
679 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
680 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
681 if line
.product_id
and line
.product_id
.membership
and not ml_ids
:
682 date_from
= line
.product_id
.membership_date_from
683 date_to
= line
.product_id
.membership_date_to
684 if line
.order_id
.date_order
> date_from
and \
685 line
.order_id
.date_order
< date_to
:
686 date_from
= line
.order_id
.date_order
687 if line
.product_id
.membership_date2date
:
688 date_from
= ('date_from' in context
689 and context
['date_from']
690 and datetime
.strptime(context
['date_from'], "%Y-%m-%d")
692 date_to
= date_from
+ relativedelta(months
= +12) # TODO: parameterize this delta?
693 date_from
= date_from
.strftime("%Y-%m-%d")
694 date_to
= date_to
.strftime("%Y-%m-%d")
695 print ("DEV: [pos_membership] [write] date_from: %s" % str(date_from
))
696 print ("DEV: [pos_membership] [write] date_to : %s" % str(date_to
))
697 member_line_obj
.create(cr
, uid
698 , { 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False
699 , 'membership_id': line
.product_id
.id
700 , 'member_price': line
.price_unit
701 , 'date': time
.strftime('%Y-%m-%d')
702 , 'date_from': date_from
704 , 'pos_order_line': line
.id
707 if line
.product_id
.membership_grouped
:
708 if line
.order_id
.partner_id
.associate_members
:
709 associate_member_line_ids
= member_line_obj
.search(cr
, uid
710 , [ ('pos_order_line', '=', line
.id)
711 , ('partner', '!=', line
.order_id
.partner_id
.id)
714 for associate_member_line
in member_line_obj
.browse(cr
, uid
, associate_member_line_ids
, context
=context
):
715 print ("DEV: [pos_membership] [write] [associate] date_from: %s" % str(date_from
))
716 print ("DEV: [pos_membership] [write] [associate] date_to : %s" % str(date_to
))
717 member_line_obj
.write(cr
, uid
, associate_member_line
.id
718 , {'date_from': date_from
723 print("DEV: mettre une contrainte pour l'objet\
724 membership.membership_line interdisant les\
725 adhésions groupées reliées à des partenaires\
726 sans membres associés")
728 associate_member_line_ids
= member_line_obj
.search(cr
, uid
729 , [ ('pos_order_line', '=', line
.id)
730 , ('partner', '!=', line
.order_id
.partner_id
.id)
733 member_line_obj
.unlink(cr
, uid
, associate_member_line_ids
, context
=context
)
735 #Define member ident if it's necessary
736 partners
= [line
.order_id
.partner_id
]
737 if line
.order_id
.partner_id
.associate_members
:
738 partners
.extend(line
.order_id
.partner_id
.associate_members
)
740 if not i
.member_ident
:
741 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
742 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
743 if line
.product_id
and not line
.product_id
.membership
and ml_ids
:
744 # Product line has changed to a non membership product
745 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
746 print("DEV: [pos_membership] [pos_order_line] [write]: res=%s" % str(res
))
749 def unlink(self
, cr
, uid
, ids
, context
=None):
750 """Remove Membership Line Record for Account Invoice Line
752 member_line_obj
= self
.pool
.get('membership.membership_line')
754 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', id)], context
=context
)
755 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
756 return super(pos_order_line
, self
).unlink(cr
, uid
, ids
, context
=context
)
758 def create(self
, cr
, uid
, vals
, context
=None):
759 member_line_obj
= self
.pool
.get('membership.membership_line')
760 print("DEV: [pos_membership] [pos_order_line] [create]: vals=%s context=%s" % (str(vals
), str(context
)))
761 res
= super(pos_order_line
, self
).create(cr
, uid
, vals
, context
=context
)
762 print ("DEV: [pos_membership] [pos_order_line] [create] [super] : res=%s" % str(res
))
763 line
= self
.browse(cr
, uid
, res
, context
=context
)
765 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
766 if line
.product_id
and line
.product_id
.membership
and not ml_ids
:
767 date_from
= line
.product_id
.membership_date_from
768 date_to
= line
.product_id
.membership_date_to
769 if line
.order_id
.date_order
> date_from
and line
.order_id
.date_order
< date_to
:
770 date_from
= line
.order_id
.date_order
771 if line
.product_id
.membership_date2date
:
772 date_from
= ('date_from' in context
773 and context
.get('date_from')
774 and datetime
.strptime(context
.get('date_from'), "%Y-%m-%d")
776 date_to
= date_from
+ relativedelta(days
= +364) # TODO: parameterize this delta?
777 date_from
= date_from
.strftime("%Y-%m-%d")
778 date_to
= date_to
.strftime("%Y-%m-%d")
779 print ("DEV: [pos_membership] [pos_order_line] [create] date_from: %s" % str(date_from
))
780 print ("DEV: [pos_membership] [pos_order_line] [create] date_to : %s" % str(date_to
))
781 member_line_obj
.create(cr
, uid
, {
782 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False,
783 'membership_id': line
.product_id
.id,
784 'member_price': line
.price_unit
,
785 'date': time
.strftime('%Y-%m-%d'),
786 'date_from': date_from
,
788 'pos_order_line': line
.id,
790 partners
= [line
.order_id
.partner_id
]
791 if line
.product_id
.membership_grouped
and line
.order_id
.partner_id
.associate_members
:
792 partners
.extend(line
.order_id
.partner_id
.associate_members
)
793 #Adding membership lines just for associate partners
794 for associate_member
in line
.order_id
.partner_id
.associate_members
:
795 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_from: %s" % str(date_from
))
796 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_to : %s" % str(date_to
))
797 member_line_obj
.create(cr
, uid
, {
798 'partner': associate_member
.id,
799 'membership_id': line
.product_id
.id,
800 'member_price': line
.price_unit
,
801 'date': time
.strftime('%Y-%m-%d'),
802 'date_from': date_from
,
804 'pos_order_line': line
.id,
806 elif line
.product_id
.membership_grouped
and not line
.order_id
.partner_id
.associate_members
:
807 raise osv
.except_osv(_('Error!!!'), _('You try to order grouped membership product to a partner who hasn\'t associated partners.'))
808 #Define member ident if it's necessary
811 print ("\033[7mXXX: [pos_membership] [pos_order_line] [create] : pos_order_line has no partner_id!\033[0m")
813 if not i
.member_ident
:
814 print ("DEV: [pos_membership] [pos_order_line] [create] [partners] : i=%s i.id=%s" % (str(i
), str(i
.id)))
815 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
816 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
817 print ("DEV: [pos_membership] [pos_order_line] [create] : return=%s" % str(res
))
822 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: