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
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_session(osv
.osv
):
43 _inherit
= 'pos.session'
45 def open_cb(self
, cr
, uid
, ids
, context
=None):
47 Avoid call the Point Of Sale interface and set the pos.session to 'opened' (in progress)
52 if isinstance(ids
, (int, long)):
55 this_record
= self
.browse(cr
, uid
, ids
[0], context
=context
)
56 this_record
._workflow
_signal
('open')
58 context
.update(active_id
=this_record
.id)
66 class pos_order(osv
.osv
):
67 _inherit
= 'pos.order'
69 def create_partner_from_ui(self
, cr
, uid
, partners
, context
=None):
70 print ("DEV: [pos_membership] [create_partner_from_ui] partners=%s" % str(partners
))
72 partner_obj
= self
.pool
.get('res.partner')
73 for tmp_partner
in partners
:
74 partner
= tmp_partner
['data']
75 partner_id
= partner_obj
.create(cr
, uid
, {
76 'name': partner
['name'],
78 partner_ids
.append(partner_id
)
79 #self.signal_paid(cr, uid, [partner_id])
82 def create_from_ui(self
, cr
, uid
, orders
, context
=None):
83 # NOTE: copied from openerp/addons/point_of_sale/point_of_sale.py
84 #_logger.info("orders: %r", orders)
85 print ("DEV: [pos_membership] [create_from_ui] order=", str(orders
))
87 for tmp_order
in orders
:
88 order
= tmp_order
['data']
89 order_id
= self
.create(cr
, uid
, {
90 'name': order
['name'],
91 'user_id': order
['user_id'] or False,
92 'session_id': order
['pos_session_id'],
93 'lines': order
['lines'],
94 'pos_reference': order
['name'],
95 #-- BEGIN pos_membership
96 'partner_id': order
['partner_id'],
97 #-- END pos_membership
100 for payments
in order
['statement_ids']:
101 payment
= payments
[2]
102 self
.add_payment(cr
, uid
, order_id
, {
103 'amount': payment
['amount'] or 0.0,
104 'payment_date': payment
['name'],
105 'statement_id': payment
['statement_id'],
106 'payment_name': payment
.get('note', False),
107 'journal': payment
['journal_id']
110 if order
['amount_return']:
111 session
= self
.pool
.get('pos.session').browse(cr
, uid
, order
['pos_session_id'], context
=context
)
112 cash_journal
= session
.cash_journal_id
113 cash_statement
= False
115 cash_journal_ids
= filter(lambda st
: st
.journal_id
.type == 'cash', session
.statement_ids
)
116 if not len(cash_journal_ids
):
117 raise osv
.except_osv(_('error!'),
118 _("No cash statement found for this session. Unable to record returned cash."))
119 cash_journal
= cash_journal_ids
[0].journal_id
120 self
.add_payment(cr
, uid
, order_id
, {
121 'amount': -order
['amount_return'],
122 'payment_date': time
.strftime('%Y-%m-%d %H:%M:%S'),
123 'payment_name': _('return'),
124 'journal': cash_journal
.id,
126 order_ids
.append(order_id
)
127 wf_service
= netsvc
.LocalService("workflow")
128 wf_service
.trg_validate(uid
, 'pos.order', order_id
, 'paid', cr
)
134 class membership_line(osv
.osv
):
136 _inherit
= 'membership.membership_line'
138 def _get_partners(self
, cr
, uid
, ids
, context
=None):
139 list_membership_line
= []
140 member_line_obj
= self
.pool
.get('membership.membership_line')
141 for partner
in self
.pool
.get('res.partner').browse(cr
, uid
, ids
, context
=context
):
142 if partner
.member_lines
:
143 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('id', 'in', [l
.id for l
in partner
.member_lines
])], context
=context
)
144 print("DEV: [pos_membership] [membership_line] [_get_partners]: ids=%s res=%s" % (str(ids
), str(list_membership_line
)))
145 return list_membership_line
147 #def _get_membership_lines_from_account_invoice(self, cr, uid, ids, context=None):
148 # list_membership_line = []
149 # member_line_obj = self.pool.get('membership.membership_line')
150 # for invoice in self.pool.get('account.invoice').browse(cr, uid, ids, context=context):
151 # if invoice.invoice_line:
152 # list_membership_line += member_line_obj.search(cr, uid, [('account_invoice_line', 'in', [ l.id for l in invoice.invoice_line])], context=context)
154 # { 'class': 'account.invoice'
155 # , 'ids': list_membership_line
157 # #res= list_membership_line
158 # print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_account_invoice]: res=%s" % str(res))
160 def _get_membership_lines_from_pos_order(self
, cr
, uid
, ids
, context
=None):
161 list_membership_line
= []
162 member_line_obj
= self
.pool
.get('membership.membership_line')
163 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: ids=%s context=%s" % (str(ids
), str(context
)))
164 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
166 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('pos_order_line', 'in', [l
.id for l
in order
.lines
])], context
=context
)
168 # { 'class': 'pos.order'
169 # , 'ids': list_membership_line
171 res
= list_membership_line
172 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: res=%s" % str(res
))
175 def _check_membership_date(self
, cr
, uid
, ids
, context
=None):
176 """Check if membership product is not in the past
177 @param self: The object pointer
178 @param cr: the current row, from the database cursor,
179 @param uid: the current user’s ID for security checks,
180 @param ids: List of Membership Line IDs
181 @param context: A standard dictionary for contextual values
185 SELECT MIN(ml.date_to - ai.date_invoice)
186 FROM membership_membership_line ml
187 JOIN account_invoice_line ail ON (
188 ml.account_invoice_line = ail.id
190 JOIN account_invoice ai ON (
191 ai.id = ail.invoice_id)
192 WHERE ml.id IN %s''', (tuple(ids
),))
195 if r
[0] and r
[0] < 0:
198 SELECT MIN(ml.date_to - ai.date_order)
199 FROM membership_membership_line ml
200 JOIN pos_order_line ail ON (
201 ml.pos_order_line = ail.id
203 JOIN pos_order ai ON (
204 ai.id = ail.order_id)
205 WHERE ml.id IN %s''', (tuple(ids
),))
208 if r
[0] and r
[0] < 0:
212 def _state(self
, cr
, uid
, ids
, name
, args
, context
=None):
213 """Compute the state lines
214 @param self: The object pointer
215 @param cr: the current row, from the database cursor,
216 @param uid: the current user’s ID for security checks,
217 @param ids: List of Membership Line IDs
218 @param name: Field Name
219 @param context: A standard dictionary for contextual values
220 @param return: Dictionary of state Value
223 print("DEV: [pos_membership] [membership_line] [_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
224 inv_obj
= self
.pool
.get('account.invoice')
225 ord_obj
= self
.pool
.get('pos.order')
226 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
228 SELECT i.state, i.id FROM
232 SELECT l.invoice_id FROM
233 account_invoice_line l WHERE
235 SELECT ml.account_invoice_line FROM
236 membership_membership_line ml WHERE
241 fetched
= cr
.fetchone()
245 if (istate
== 'draft') |
(istate
== 'proforma'):
247 elif istate
== 'open':
249 elif istate
== 'paid':
251 inv
= inv_obj
.browse(cr
, uid
, fetched
[1], context
=context
)
252 for payment
in inv
.payment_ids
:
253 if payment
.invoice
and payment
.invoice
.type == 'out_refund':
255 elif istate
== 'cancel':
260 SELECT i.state, i.id FROM
264 SELECT l.order_id FROM
265 pos_order_line l WHERE
267 SELECT ml.pos_order_line FROM
268 membership_membership_line ml WHERE
273 fetched
= cr
.fetchone()
275 res
[line
.id] = 'canceled'
277 print("DEV: [pos_membership] [membership_line] [_state]: line.partner.id=%s" % (str(line
.partner
.id)))
278 self
.write(cr
, uid
, line
.id, {'partner': line
.partner
.id})
279 # NOTE: force une mise à jour du partner,
280 # car il n'y en a pas lors de la création du pos.order
281 # dans le PoS (pour le moment)
282 partner_obj
= self
.pool
.get('res.partner')
283 for partner
in partner_obj
.browse(cr
, uid
, [line
.partner
.id], context
=context
):
284 if not partner
.member_ident
:
285 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
286 partner_obj
.write(cr
, uid
, partner
.id, {'member_ident': mbr_id
})
289 if (ostate
== 'paid') |
(ostate
== 'draft'):
291 elif (ostate
== 'done') |
(ostate
== 'invoiced'):
293 # XXX: regarder l'équivalent de out_refund pour un pos.order
294 print("DEV: [pos_membership] [membership_line] [_state]: paid: TODO")
295 #inv = ord_obj.browse(cr, uid, fetched[1], context=context)
296 #for payment in inv.payment_ids:
297 # if payment.invoice and payment.invoice.type == 'out_refund':
299 elif ostate
== 'cancel':
302 print("DEV: [pos_membership] [membership_line] [_state]: return=%s" % (str(res
)))
305 def write(self
, cr
, uid
, ids
, vals
, context
=None):
306 print("DEV: [pos_membership] [membership_line] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
307 res
= super(membership_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
308 print("DEV: [pos_membership] [membership_line] [write]: res=%s" % str(res
))
311 def create(self
, cr
, uid
, vals
, context
=None):
312 print("DEV: [pos_membership] [membership_line] [create]: vals=%s" % (str(vals
)))
313 member_line_obj
= self
.pool
.get('membership.membership_line')
314 res
= super(membership_line
, self
).create(cr
, uid
, vals
, context
=context
)
315 print("DEV: [pos_membership] [membership_line] [create]: res=%s" % (str(res
)))
319 'pos_order_line': fields
.many2one('pos.order.line', 'POS Order line', readonly
=True),
320 'pos_order_id': fields
.related('pos_order_line', 'order_id', type='many2one', relation
='pos.order', string
='Order', readonly
=True),
321 'state': fields
.function(_state
,
322 string
='Membership Status', type='selection',
325 #'account.invoice': (_get_membership_lines_from_account_invoice, ['state'], 10),
326 # NOTE: déjà géré par membership.membership_line._get_membership_lines
327 'pos.order': (_get_membership_lines_from_pos_order
, ['state', 'partner_id'], 10),
328 'res.partner': (_get_partners
, ['membership_state'], 12),
329 }, help="""It indicates the membership status.
330 -Non Member: A member who has not applied for any membership.
331 -Cancelled Member: A member who has cancelled his membership.
332 -Old Member: A member whose membership date has expired.
333 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
334 -Invoiced Member: A member whose invoice has been created.
335 -Paid Member: A member who has paid the membership amount."""),
336 'company_id': fields
.related('account_invoice_line', 'invoice_id', 'company_id', type="many2one", relation
="res.company", string
="Company", readonly
=True, store
=True)
337 # XXX: pos_order_line a aussi un company_id
343 class Partner(osv
.osv
):
345 _inherit
= 'res.partner'
347 def _get_partner_id(self
, cr
, uid
, ids
, context
=None):
348 print("DEV: [pos_membership] [Partner] [_get_partner_id]: ids=%s context=%s" % (str(ids
), str(context
)))
349 member_line_obj
= self
.pool
.get('membership.membership_line')
350 res_obj
= self
.pool
.get('res.partner')
351 data_inv
= member_line_obj
.browse(cr
, uid
, ids
, context
=context
)
353 for data
in data_inv
:
354 list_partner
.append(data
.partner
.id)
357 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
359 print("DEV: [pos_membership] [Partner] [_get_partner_id]: res=%s" % (str(list_partner
)))
362 def _get_invoice_partner(self
, cr
, uid
, ids
, context
=None):
363 inv_obj
= self
.pool
.get('account.invoice')
364 res_obj
= self
.pool
.get('res.partner')
365 data_inv
= inv_obj
.browse(cr
, uid
, ids
, context
=context
)
367 for data
in data_inv
:
368 list_partner
.append(data
.partner_id
.id)
371 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
375 def _get_order_partner(self
, cr
, uid
, ids
, context
=None):
376 ord_obj
= self
.pool
.get('pos.order')
377 res_obj
= self
.pool
.get('res.partner')
378 data_ord
= ord_obj
.browse(cr
, uid
, ids
, context
=context
)
380 for data
in data_ord
:
381 list_partner
.append(data
.partner_id
.id)
384 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
388 def _membership_state(self
, cr
, uid
, ids
, name
, args
, context
=None):
389 """This Function return Membership State For Given Partner.
390 @param self: The object pointer
391 @param cr: the current row, from the database cursor,
392 @param uid: the current user’s ID for security checks,
393 @param ids: List of Partner IDs
394 @param name: Field Name
395 @param context: A standard dictionary for contextual values
396 @param return: Dictionary of Membership state Value
399 print("DEV: [pos_membership] [Partner] [_membership_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
402 today
= time
.strftime('%Y-%m-%d')
404 print("DEV: [pos_membership] [Partner] [_membership_state] id=%s" % (str(id)))
405 partner_data
= self
.browse(cr
, uid
, id, context
=context
)
406 if partner_data
.membership_cancel
and today
> partner_data
.membership_cancel
:
409 if partner_data
.membership_stop
and today
> partner_data
.membership_stop
:
413 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines] [test]")
414 if partner_data
.member_lines
:
415 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines]" % ())
416 for mline
in partner_data
.member_lines
:
417 print("DEV: [pos_membership] [Partner] [_membership_state] [mline]: id=%s" % str(mline
.id))
418 if mline
.date_to
>= today
:
419 if mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
:
420 istate
= mline
.account_invoice_line
.invoice_id
.state
421 print("DEV: [pos_membership] [Partner] [_membership_state] [account_invoice_line]: id=%s istate=%s" % (str(mline
.account_invoice_line
.invoice_id
.id), str(istate
)))
424 inv
= mline
.account_invoice_line
.invoice_id
425 for payment
in inv
.payment_ids
:
426 if payment
.invoice
.type == 'out_refund':
429 elif istate
== 'open' and s
!= 0:
431 elif istate
== 'cancel' and s
!= 0 and s
!= 1:
433 elif (istate
== 'draft' or istate
== 'proforma') and s
!= 0 and s
!= 1:
435 elif mline
.pos_order_line
and mline
.pos_order_line
.order_id
:
436 ostate
= mline
.pos_order_line
.order_id
.state
437 print("DEV: [pos_membership] [Partner] [_membership_state] [pos_order_line]: id=%s ostate=%s" % (str(mline
.pos_order_line
.order_id
.id), str(ostate
)))
438 if ostate
== 'paid' and s
!= 0 and s
!= 1:
440 if ostate
== 'invoiced':
444 # XXX: regarder l'équivalent de out_refund pour un pos.order
445 print("DEV: [pos_membership] [partner] [_membership_state]: paid: TODO")
446 #inv = mline.pos_order_line.order_id
447 #for payment in inv.payment_ids:
448 # if payment.invoice.type == 'out_refund':
451 elif ostate
== 'open' and s
!= 0:
452 # XXX: 1 donne invoiced, c'est pitet pas bon
453 print("DEV: [pos_membership] [partner] [_membership_state]: invoiced: TODO")
455 elif ostate
== 'cancel' and s
!= 0 and s
!= 1:
457 elif ostate
== 'draft' and s
!= 0 and s
!= 1:
460 # when we don't have an invoice line only use the date to get the state.
464 for mline
in partner_data
.member_lines
:
465 if mline
.date_from
< today
and \
466 mline
.date_to
< today
and \
467 mline
.date_from
<= mline
.date_to
and \
468 ((mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
.state
) == 'paid' or \
469 (mline
.pos_order_line
and \
470 (mline
.pos_order_line
.order_id
.state
== 'paid' or \
471 mline
.pos_order_line
.order_id
.state
== 'done' or \
472 mline
.pos_order_line
.order_id
.state
== 'invoiced' ))):
488 if partner_data
.free_member
and s
!= 0:
490 if partner_data
.associate_member
:
491 res_state
= self
._membership
_state
(cr
, uid
, [partner_data
.associate_member
.id], name
, args
, context
=context
)
492 res
[id] = res_state
[partner_data
.associate_member
.id]
493 print("DEV: [pos_membership] [Partner] [_membership_state]: res=%s" % (str(res
)))
496 def _membership_date(self
, cr
, uid
, ids
, name
, args
, context
=None):
497 """Return date of membership"""
500 member_line_obj
= self
.pool
.get('membership.membership_line')
501 print("DEV: [pos_membership] [Partner] [_membership_date]: ids=%s" % (str(ids
)))
502 for partner
in self
.browse(cr
, uid
, ids
, context
=context
):
503 if partner
.associate_member
:
504 partner_id
= partner
.associate_member
.id
506 partner_id
= partner
.id
508 'membership_start': False,
509 'membership_stop': False,
510 'membership_cancel': False
512 if name
== 'membership_start':
513 line_id
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
514 limit
=1, order
='date_from', context
=context
)
516 res
[partner
.id]['membership_start'] = member_line_obj
.read(cr
, uid
, line_id
[0],
517 ['date_from'], context
=context
)['date_from']
518 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_start]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_start'])))
520 if name
== 'membership_stop':
521 line_id1
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
522 limit
=1, order
='date_to desc', context
=context
)
524 res
[partner
.id]['membership_stop'] = member_line_obj
.read(cr
, uid
, line_id1
[0],
525 ['date_to'], context
=context
)['date_to']
526 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_stop]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_stop'])))
528 if name
== 'membership_cancel':
529 if partner
.membership_state
== 'canceled':
530 line_id2
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner
.id)], limit
=1, order
='date_cancel', context
=context
)
532 res
[partner
.id]['membership_cancel'] = member_line_obj
.read(cr
, uid
, line_id2
[0], ['date_cancel'], context
=context
)['date_cancel']
533 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_cancel]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_cancel'])))
534 print("DEV: [pos_membership] [Partner] [_membership_date]: res=%s" % (str(res
)))
537 def _get_partners(self
, cr
, uid
, ids
, context
=None):
540 ids2
= self
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
544 def __get_membership_state(self
, *args
, **kwargs
):
545 return self
._membership
_state
(*args
, **kwargs
)
548 'membership_state': fields
.function(
549 __get_membership_state
,
550 string
= 'Current Membership Status', type = 'selection',
553 # NOTE: il est important que la priorité soit plus grande
554 # que les membership_{start,stop,cancel}
555 # car _membership_state s'en sert et doit donc les trouver à jour.
556 'account.invoice': (_get_invoice_partner
, ['state'], 20),
557 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 20),
558 'membership.membership_line': (_get_partner_id
, ['state'], 20),
559 'res.partner': (_get_partners
, ['free_member', 'membership_state', 'associate_member'], 20)
560 }, help="""It indicates the membership state.
561 -Non Member: A partner who has not applied for any membership.
562 -Cancelled Member: A member who has cancelled his membership.
563 -Old Member: A member whose membership date has expired.
564 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
565 -Invoiced Member: A member whose invoice has been created.
566 -Paying member: A member who has paid the membership fee."""),
567 'membership_start': fields
.function(
568 _membership_date
, multi
= 'membership_start',
569 string
= 'Membership Start Date', type = 'date',
571 'account.invoice': (_get_invoice_partner
, ['state'], 10),
572 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
573 'membership.membership_line': (_get_partner_id
, ['state'], 10),
574 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
575 }, help="Date from which membership becomes active."),
576 'membership_stop': fields
.function(
578 string
= 'Membership End Date', type='date', multi
='membership_stop',
580 'account.invoice': (_get_invoice_partner
, ['state'], 10),
581 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
582 'membership.membership_line': (_get_partner_id
, ['state'], 10),
583 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
584 }, help="Date until which membership remains active."),
585 'membership_cancel': fields
.function(
587 string
= 'Cancel Membership Date', type='date', multi
='membership_cancel',
589 'account.invoice': (_get_invoice_partner
, ['state'], 11),
590 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 11),
591 'membership.membership_line': (_get_partner_id
, ['state'], 10),
592 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
593 }, help="Date on which membership has been cancelled"),
598 class pos_order(osv
.osv
):
599 _inherit
= 'pos.order'
601 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py
602 def action_invoice(self
, cr
, uid
, ids
, context
=None):
603 print ("DEV: [pos_membership] [pos_order] [action_invoice]")
604 wf_service
= netsvc
.LocalService("workflow")
605 inv_ref
= self
.pool
.get('account.invoice')
606 inv_line_ref
= self
.pool
.get('account.invoice.line')
607 product_obj
= self
.pool
.get('product.product')
610 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
612 inv_ids
.append(order
.invoice_id
.id)
615 if not order
.partner_id
:
616 raise osv
.except_osv(_('Error!'), _('Please provide a partner for the sale.'))
618 acc
= order
.partner_id
.property_account_receivable
.id
619 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py to fix account.invoice.line creation
622 'origin': order
.name
,
624 'journal_id': order
.sale_journal
.id or None,
625 'type': 'out_invoice',
626 'reference': order
.name
,
627 'partner_id': order
.partner_id
.id,
628 'comment': order
.note
or '',
629 'currency_id': order
.pricelist_id
.currency_id
.id, # considering partner's sale pricelist's currency
632 inv
.update(inv_ref
.onchange_partner_id(cr
, uid
, [], 'out_invoice', order
.partner_id
.id)['value'])
633 if not inv
.get('account_id', None):
634 inv
['account_id'] = acc
635 for line
in order
.lines
:
637 #'invoice_id': inv_id,
638 'product_id': line
.product_id
.id,
639 'quantity': line
.qty
,
641 inv_name
= product_obj
.name_get(cr
, uid
, [line
.product_id
.id], context
=context
)[0][1]
642 inv_line
.update(inv_line_ref
.product_id_change(cr
, uid
, [],
644 line
.product_id
.uom_id
.id,
645 line
.qty
, partner_id
= order
.partner_id
.id,
646 fposition_id
=order
.partner_id
.property_account_position
.id)['value'])
647 if line
.product_id
.description_sale
:
648 inv_line
['note'] = line
.product_id
.description_sale
649 inv_line
['price_unit'] = line
.price_unit
650 inv_line
['discount'] = line
.discount
651 inv_line
['name'] = inv_name
652 inv_line
['invoice_line_tax_id'] = [(6, 0, [x
.id for x
in line
.product_id
.taxes_id
] )]
653 inv_line_ref
.create(cr
, uid
, inv_line
, context
=context
)
654 #inv_line_ref.create(cr, uid, inv_line, context=context)
655 inv
['invoice_line'].append((0, 0, inv_line
))
656 inv_id
= inv_ref
.create(cr
, uid
, inv
, context
=context
)
658 self
.write(cr
, uid
, [order
.id], {'invoice_id': inv_id
, 'state': 'invoiced'}, context
=context
)
659 inv_ref
.confirm_paid(cr
, uid
, [inv_id
], context
=context
)
660 inv_ids
.append(inv_id
)
661 inv_ref
.button_reset_taxes(cr
, uid
, [inv_id
], context
=context
)
662 wf_service
.trg_validate(uid
, 'pos.order', order
.id, 'invoice', cr
)
664 if not inv_ids
: return {}
666 mod_obj
= self
.pool
.get('ir.model.data')
667 res
= mod_obj
.get_object_reference(cr
, uid
, 'account', 'invoice_form')
668 res_id
= res
and res
[1] or False
670 'name': _('Customer Invoice'),
674 'res_model': 'account.invoice',
675 'context': "{'type':'out_invoice'}",
676 'type': 'ir.actions.act_window',
679 'res_id': inv_ids
and inv_ids
[0] or False,
682 def write(self
, cr
, uid
, ids
, vals
, context
=None):
683 print("DEV: [pos_membership] [pos_order] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
684 pos_order_obj
= self
.pool
.get('pos.order')
685 res
= super(pos_order
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
686 print("DEV: [pos_membership] [pos_order] [write]: res=%s" % str(res
))
689 def create(self
, cr
, uid
, vals
, context
=None):
690 print("DEV: [pos_membership] [pos_order] [create]: vals=%s" % (str(vals
)))
691 pos_order_obj
= self
.pool
.get('pos.order')
692 res
= super(pos_order
, self
).create(cr
, uid
, vals
, context
=context
)
693 print("DEV: [pos_membership] [pos_order] [create]: res=%s" % (str(res
)))
698 class pos_order_line(osv
.osv
):
699 _inherit
= 'pos.order.line'
701 def write(self
, cr
, uid
, ids
, vals
, context
=None):
702 print("DEV: [pos_membership] [pos_order_line] [write]: ids=%s vals=%s context=%s" % (str(ids
), str(vals
), str(context
)))
703 member_line_obj
= self
.pool
.get('membership.membership_line')
704 res
= super(pos_order_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
705 print ("DEV: [pos_membership] [pos_order_line] [write] [super] : res=%s" % str(res
))
706 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
707 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
708 if line
.product_id
and line
.product_id
.membership
:
709 member_line_id
= member_line_obj
.search(cr
, uid
710 , [('partner', '=', line
.order_id
.partner_id
.id)
711 ,('pos_order_line', '=', line
.id)]
714 for member_line
in member_line_obj
.browse(cr
, uid
, member_line_id
, context
=context
):
715 # NOTE: get member_line created in pos_membership.pos_order_line.create
716 date_from
= member_line
.date_from
717 date_to
= member_line
.date_to
718 if line
.product_id
.membership_date2date
:
719 date_from
= ('date_from' in context
720 and context
.get('date_from')
721 and datetime
.strptime(context('date_from'), "%Y-%m-%d")
723 date_to
= date_from
+ relativedelta(months
= +12) # TODO: parameterize this delta?
724 date_from
= date_from
.strftime("%Y-%m-%d")
725 date_to
= date_to
.strftime("%Y-%m-%d")
726 print ("DEV: [pos_membership] [pos_order_line] [write] date_from: %s" % str(date_from
))
727 print ("DEV: [pos_membership] [pos_order_line] [write] date_to : %s" % str(date_to
))
728 member_line_obj
.write(cr
, uid
, member_line
.id
729 , {'date_from': date_from
733 if line
.product_id
.membership_grouped
:
734 if line
.order_id
.partner_id
.associate_members
:
735 associate_member_line_ids
= member_line_obj
.search(cr
, uid
736 , [ ('pos_order_line', '=', line
.id)
737 , ('partner', '!=', line
.order_id
.partner_id
.id)
740 for associate_member_line
in member_line_obj
.browse(cr
, uid
, associate_member_line_ids
, context
=context
):
741 print ("DEV: [pos_membership] [pos_order_line] [write] [associate] date_from: %s" % str(date_from
))
742 print ("DEV: [pos_membership] [pos_order_line] [write] [associate] date_to : %s" % str(date_to
))
743 member_line_obj
.write(cr
, uid
, associate_member_line
.id
744 , {'date_from': date_from
749 print("DEV: mettre une contrainte pour l'objet\
750 membership.membership_line interdisant les\
751 adhésions groupées reliées à des partenaires\
752 sans membres associés")
754 associate_member_line_ids
= member_line_obj
.search(cr
, uid
755 , [ ('pos_order_line', '=', line
.id)
756 , ('partner', '!=', line
.order_id
.partner_id
.id)
759 member_line_obj
.unlink(cr
, uid
, associate_member_line_ids
, context
=context
)
760 #Define member ident if it's necessary
761 partners
= [line
.order_id
.partner_id
]
762 if line
.order_id
.partner_id
.associate_members
:
763 partners
.extend(line
.order_id
.partner_id
.associate_members
)
765 if not i
.member_ident
:
766 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
767 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
768 if line
.product_id
and not line
.product_id
.membership
and ml_ids
:
769 # Product line has changed to a non membership product
770 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
771 print ("DEV: [pos_membership] [pos_order_line] [write] : return=%s" % str(res
))
774 def unlink(self
, cr
, uid
, ids
, context
=None):
775 """Remove Membership Line Record for Account Invoice Line
777 member_line_obj
= self
.pool
.get('membership.membership_line')
779 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', id)], context
=context
)
780 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
781 return super(pos_order_line
, self
).unlink(cr
, uid
, ids
, context
=context
)
783 def create(self
, cr
, uid
, vals
, context
=None):
784 member_line_obj
= self
.pool
.get('membership.membership_line')
785 print("DEV: [pos_membership] [pos_order_line] [create]: vals=%s context=%s" % (str(vals
), str(context
)))
786 res
= super(pos_order_line
, self
).create(cr
, uid
, vals
, context
=context
)
787 print ("DEV: [pos_membership] [pos_order_line] [create] [super] : res=%s" % str(res
))
788 line
= self
.browse(cr
, uid
, res
, context
=context
)
790 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
791 if line
.product_id
and line
.product_id
.membership
and not ml_ids
:
792 date_from
= line
.product_id
.membership_date_from
793 date_to
= line
.product_id
.membership_date_to
794 if line
.order_id
.date_order
> date_from
and line
.order_id
.date_order
< date_to
:
795 date_from
= line
.order_id
.date_order
796 if line
.product_id
.membership_date2date
:
797 date_from
= ('date_from' in context
798 and context
.get('date_from')
799 and datetime
.strptime(context
.get('date_from'), "%Y-%m-%d")
801 date_to
= date_from
+ relativedelta(days
= +364) # TODO: parameterize this delta?
802 date_from
= date_from
.strftime("%Y-%m-%d")
803 date_to
= date_to
.strftime("%Y-%m-%d")
804 print ("DEV: [pos_membership] [pos_order_line] [create] date_from: %s" % str(date_from
))
805 print ("DEV: [pos_membership] [pos_order_line] [create] date_to : %s" % str(date_to
))
806 member_line_obj
.create(cr
, uid
, {
807 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False,
808 'membership_id': line
.product_id
.id,
809 'member_price': line
.price_unit
,
810 'date': time
.strftime('%Y-%m-%d'),
811 'date_from': date_from
,
813 'pos_order_line': line
.id,
815 partners
= [line
.order_id
.partner_id
]
816 if line
.product_id
.membership_grouped
and line
.order_id
.partner_id
.associate_members
:
817 partners
.extend(line
.order_id
.partner_id
.associate_members
)
818 #Adding membership lines just for associate partners
819 for associate_member
in line
.order_id
.partner_id
.associate_members
:
820 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_from: %s" % str(date_from
))
821 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_to : %s" % str(date_to
))
822 member_line_obj
.create(cr
, uid
, {
823 'partner': associate_member
.id,
824 'membership_id': line
.product_id
.id,
825 'member_price': line
.price_unit
,
826 'date': time
.strftime('%Y-%m-%d'),
827 'date_from': date_from
,
829 'pos_order_line': line
.id,
831 elif line
.product_id
.membership_grouped
and not line
.order_id
.partner_id
.associate_members
:
832 raise osv
.except_osv(_('Error!!!'), _('You try to order grouped membership product to a partner who hasn\'t associated partners.'))
833 #Define member ident if it's necessary
836 print ("\033[7mXXX: [pos_membership] [pos_order_line] [create] : pos_order_line has no partner_id!\033[0m")
838 if not i
.member_ident
:
839 print ("DEV: [pos_membership] [pos_order_line] [create] [partners] : i=%s i.id=%s" % (str(i
), str(i
.id)))
840 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
841 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
842 print ("DEV: [pos_membership] [pos_order_line] [create] : return=%s" % str(res
))
847 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: