~therp-nl/banking-addons/6.1-lp933472-bic-not-required

« back to all changes in this revision

Viewing changes to account_direct_debit/model/account_payment.py

  • Committer: OpenERP instance user
  • Date: 2011-12-14 14:35:02 UTC
  • Revision ID: oersmldev6@midgard.therp.nl-20111214143502-0cmmvonqv7w1dhx0
[FIX] Bank import writes to browse object
[ADD] direct debit order: process storno during bank import
[ADD] bank import: add hooks for processing debit orders and stornos
[ADD] direct debit order: pre-select move lines on reference substring
        configured in payment mode
[ADD] payment term for direct debit invoices
[ADD] payment line views: add storno field
[RFR] standardize storno and debit order processing during bank import

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
            help=('Journal to write payment entries when confirming ' +
20
20
                  'a debit order of this mode'),
21
21
            ),
 
22
        'reference_filter': fields.char(
 
23
            'Reference filter', size=16,
 
24
            help=(
 
25
                'Optional substring filter on move line references. ' +
 
26
                'You can use this in combination with a specific journal ' +
 
27
                'for items that you want to handle with this mode. Use ' +
 
28
                'a separate sequence for the journal with a distinguished ' +
 
29
                'prefix or suffix and enter that character string here.'),
 
30
            ),
 
31
#        'payment_term_ids': fields.many2many(
 
32
#            'account.payment.term', 'account_payment_order_terms_rel', 
 
33
#            'mode_id', 'term_id', 'Payment terms',
 
34
#            help=('Limit selected invoices to invoices with these payment ' +
 
35
#                  'terms')
 
36
#            ),
22
37
        }
23
38
payment_mode()
24
39
 
77
92
            for line in order_line.debit_move_line_id.move_id.line_id:
78
93
                if line.account_id.type == 'other' and not line.reconcile_id:
79
94
                    line_ids.append(line.id)
80
 
        import pdb
81
 
        pdb.set_trace()
82
95
        if is_zero(order.line_ids[0].debit_move_line_id,
83
96
                   get_balance(line_ids) - amount):
84
97
            reconcile_id = self.pool.get('account.move.reconcile').create(
85
98
                cr, uid, 
86
99
                {'type': 'auto', 'line_id': [(6, 0, line_ids)]},
87
100
                context)
 
101
            # set direct debit order to finished state
 
102
            wf_service = netsvc.LocalService('workflow')
 
103
            wf_service.trg_validate(
 
104
                uid, 'payment.order', payment_order_id, 'done', cr)
 
105
 
88
106
        return reconcile_id
89
107
 
90
108
    def action_sent(self, cr, uid, ids, context=None):
165
183
class payment_line(osv.osv):
166
184
    _inherit = 'payment.line'
167
185
 
168
 
    def debit_storno(self, cr, uid, payment_line_id, storno_move_line_id, context=None):
169
 
        """
170
 
        Process a payment line from a direct debit order which has
171
 
        been canceled by the bank or by the user:
172
 
        - Undo the reconciliation of the payment line with the move
173
 
        line that it originated from, and re-reconciliated with
174
 
        the credit payment in the bank journal of the same amount and
175
 
        on the same account.
176
 
        - Mark the payment line for being reversed.
177
 
        
178
 
        :param payment_line_id: the single id of the canceled payment line
179
 
        :param storno_move_line_id: the credit payment in the bank journal
180
 
        """
181
 
 
182
 
        if isinstance(payment_line_id, (list, tuple)):
183
 
            payment_line_id = payment_line_id[0]
 
186
    def debit_storno(self, cr, uid, payment_line_id, amount,
 
187
                     currency_id, storno_retry=True, context=None):
 
188
        """
 
189
        The processing of a storno is triggered by a debit
 
190
        transfer on one of the company's bank accounts.
 
191
        This method offers to re-reconcile the original debit
 
192
        payment. For this purpose, we have registered that
 
193
        payment move on the payment line.
 
194
 
 
195
        Return the (now incomplete) reconcile id. The caller MUST
 
196
        re-reconcile this reconcile with the bank transfer and
 
197
        re-open the associated invoice.
 
198
 
 
199
        :param payment_line_id: the single payment line id
 
200
        :param amount: the (signed) amount debited from the bank account
 
201
        :param currency_id: the bank account's currency id
 
202
        :param boolean storno_retry: when True, attempt to reopen the invoice, \
 
203
        set the invoice to 'Debit denied' otherwise.
 
204
        :return: an incomplete reconcile for the caller to fill
 
205
        :rtype: database id of an account.move.reconcile resource.
 
206
        """
 
207
 
 
208
        move_line_obj = self.pool.get('account.move.line')
184
209
        reconcile_obj = self.pool.get('account.move.reconcile')
185
 
        move_line_obj = self.pool.get('account.move.line')
186
 
        payment_line = self.browse(cr, uid, payment_line_id, context=context)
187
 
 
188
 
        debit_move_line = payment_line.debit_move_line_id
189
 
        if (not debit_move_line):
190
 
            raise osv.except_osv(
191
 
                _('Can not process storno'),
192
 
                _('No move line for line %s') % payment_line.name)
193
 
        if payment_line.storno:
194
 
            raise osv.except_osv(
195
 
                _('Can not process storno'),
196
 
                _('Cancelation of payment line \'%s\' has already been ' +
197
 
                  'processed') % payment_line.name)
198
 
 
199
 
        def is_zero(total):
200
 
            return self.pool.get('res.currency').is_zero(
201
 
                cr, uid, debit_move_line.company_id.currency_id, total)
202
 
 
203
 
        # check validity of the proposed move line
204
 
        torec_move_line = move_line_obj.browse(
205
 
            cr, uid, storno_move_line_id, context=context)
206
 
        if not (is_zero(torec_move_line.debit - debit_move_line.debit) and
207
 
                is_zero(torec_move_line.credit - debit_move_line.credit) and
208
 
                torec_move_line.account_id.id == debit_move_line.account_id.id):
209
 
            raise osv.except_osv(
210
 
                _('Can not process storno'),
211
 
                _('%s is not a drop-in replacement for %s') % (
212
 
                    torec_move_line.name, debit_move_line.name))
213
 
        if payment_line.storno:
214
 
            raise osv.except_osv(
215
 
                _('Can not process storno'),
216
 
                _('Debit order line %s has already been cancelled') % (
217
 
                    payment_line.name))
218
 
 
219
 
        # replace move line in reconciliation
 
210
        line = self.browse(cr, uid, payment_line_id)
220
211
        reconcile_id = False
221
 
        if (payment_line.move_line_id.reconcile_partial_id and 
222
 
            debit_move_line_id.id in
223
 
            payment_line.move_line_id.reconcile_partial_id.line_partial_ids):
224
 
            reconcile_id = payment_line.move_line_id.reconcile_partial_id
225
 
            vals = {
226
 
                'line_partial_ids': 
227
 
                [(3, debit_move_line_id.id), (4, torec_move_line.id)],
228
 
                }
229
 
        elif (payment_line.move_line_id.reconcile_id and 
230
 
              debit_move_line_id.id in
231
 
              payment_line.move_line_id.reconcile_id.line_id):
232
 
            reconcile_id = payment_line.move_line_id.reconcile_id
233
 
            vals = {
234
 
                'line_id':
235
 
                    [(3, debit_move_line_id.id), (4, torec_move_line.id)]
236
 
                }
237
 
        if not reconcile_id:
238
 
            raise osv.except_osv(
239
 
                _('Can not perform storno'),
240
 
                _('Debit order line %s does not occur in the list of '
241
 
                  'reconciliation move lines of its origin') % 
242
 
                debit_move_line_id.name)
243
 
        reconcile_obj.write(cr, uid, reconcile_id, vals, context=context)
244
 
        self.write(cr, uid, payment_line_id, {'storno': True}, context=context)
245
 
        #for line_id in line_ids:
246
 
        #    netsvc.LocalService("workflow").trg_trigger(
247
 
        #        uid, 'account.move.line', line_id, cr)
 
212
        if (line.debit_move_line_id and not line.storno and
 
213
            self.pool.get('res.currency').is_zero(
 
214
                cr, uid, currency_id, (
 
215
                    (line.debit_move_line_id.credit or 0.0) -
 
216
                    (line.debit_move_line_id.debit or 0.0) + amount))):
 
217
            # Two different cases, full and partial
 
218
            # Both cases differ subtly in the procedure to follow
 
219
            # Needs refractoring, but why is this not in the OpenERP API?
 
220
            if line.debit_move_line_id.reconcile_partial_id:
 
221
                reconcile_id = line.debit_move_line_id.reconcile_partial_id.id
 
222
                attribute = 'reconcile_partial_id'
 
223
                if len(line.debit_move_line_id.reconcile_id.line_partial_ids) == 2:
 
224
                    # reuse the simple reconcile for the storno transfer
 
225
                    reconcile_obj.write(
 
226
                        cr, uid, reconcile_id, {
 
227
                            'line_id': [(6, 0, line.debit_move_line_id.id)],
 
228
                            'line_partial_ids': [(6, 0, [])],
 
229
                            }, context=context)
 
230
                else:
 
231
                    # split up the original reconcile in a partial one
 
232
                    # and a new one for reconciling the storno transfer
 
233
                    reconcile_obj.write(
 
234
                        cr, uid, reconcile_id, {
 
235
                            'line_partial_ids': [(3, line.debit_move_line_id.id)],
 
236
                            }, context=context)
 
237
                    reconcile_id = reconcile_obj.create(
 
238
                        cr, uid, {
 
239
                            'type': 'auto',
 
240
                            'line_id': [(6, 0, line.debit_move_line_id.id)],
 
241
                            }, context=context)
 
242
            elif line.debit_move_line_id.reconcile_id:
 
243
                reconcile_id = line.debit_move_line_id.reconcile_id.id
 
244
                if len(line.debit_move_line_id.reconcile_id.line_id) == 2:
 
245
                    # reuse the simple reconcile for the storno transfer
 
246
                    reconcile_obj.write(
 
247
                        cr, uid, reconcile_id, {
 
248
                            'line_id': [(6, 0, [line.debit_move_line_id.id])]
 
249
                            }, context=context)
 
250
                else:
 
251
                    # split up the original reconcile in a partial one
 
252
                    # and a new one for reconciling the storno transfer
 
253
                    partial_ids = [ 
 
254
                        x.id for x in line.debit_move_line_id.reconcile_id.line_id
 
255
                        if x.id != line.debit_move_line_id.id
 
256
                        ]
 
257
                    reconcile_obj.write(
 
258
                        cr, uid, reconcile_id, {
 
259
                            'line_partial_ids': [(6, 0, partial_ids)],
 
260
                            'line_id': [(6, 0, [])],
 
261
                            }, context=context)
 
262
                    reconcile_id = reconcile_obj.create(
 
263
                        cr, uid, {
 
264
                            'type': 'auto',
 
265
                            'line_id': [(6, 0, line.debit_move_line_id.id)],
 
266
                            }, context=context)
 
267
            # mark the payment line for storno processed
 
268
            if reconcile_id:
 
269
                self.write(cr, uid, [payment_line_id],
 
270
                           {'storno': True}, context=context)
 
271
                # put forth the invoice workflow
 
272
                if line.move_line_id.invoice:
 
273
                    activity = (storno_retry and 'open_test'
 
274
                                or 'invoice_debit_denied')
 
275
                    netsvc.LocalService("workflow").trg_validate(
 
276
                        uid, 'account.invoice', line.move_line_id.invoice.id,
 
277
                        activity, cr)
 
278
        return reconcile_id
248
279
 
249
280
    def debit_reconcile(self, cr, uid, payment_line_id, context=None):
250
281
        """
356
387
        payment = self.pool.get('payment.order').browse(cr, uid, context['active_id'], context=context)
357
388
        # Search for move line to pay:
358
389
        if payment.payment_order_type == 'debit':
359
 
            domain = [('reconcile_id', '=', False), ('account_id.type', '=', 'receivable'), ('amount_to_receive', '>', 0)]
 
390
            domain = [
 
391
                ('reconcile_id', '=', False),
 
392
                ('account_id.type', '=', 'receivable'),
 
393
                ('amount_to_receive', '>', 0),
 
394
                ]
 
395
            # cannot filter on properties of (searchable)
 
396
            # function fields. Needs work in expression.expression.parse()
 
397
            # Currently gives an SQL error.
 
398
#            # apply payment term filter
 
399
#            if payment.mode.payment_term_ids:
 
400
#                term_ids = [term.id for term in payment.mode.payment_term_ids]
 
401
#                domain = domain + [
 
402
#                    '|', ('invoice', '=', False),
 
403
#                    ('invoice.payment_term', 'in', term_ids),
 
404
#                    ]
360
405
        else:
361
 
            domain = [('reconcile_id', '=', False), ('account_id.type', '=', 'payable'), ('amount_to_pay', '>', 0)]
 
406
            domain = [
 
407
                ('reconcile_id', '=', False),
 
408
                ('account_id.type', '=', 'payable'),
 
409
                ('amount_to_pay', '>', 0)
 
410
                ]
 
411
        if payment.mode.reference_filter:
 
412
            domain.append(('ref', 'ilike', payment.mode.reference_filter))
362
413
        # domain = [('reconcile_id', '=', False), ('account_id.type', '=', 'payable'), ('amount_to_pay', '>', 0)]
363
414
        ### end account_direct_debit ###
364
415