~therp-nl/banking-addons/ba61-lp1098699-fix_clieop_rounding_issue

« back to all changes in this revision

Viewing changes to account_banking/bank_import_transaction.py

  • Committer: Stefan Rijnhart
  • Date: 2012-01-08 10:59:55 UTC
  • Revision ID: stefan@therp.nl-20120108105955-n0him1h8iyxu6hd3
[FIX] streamlined currency and company resolving
[FIX] default country for new partners in foreign bank account
[FIX] cannot match a confirmed transaction

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
    _name = 'banking.import.transaction'
52
52
    _description = 'Bank import transaction'
53
53
    _rec_name = 'transaction'
 
54
 
54
55
    signal_duplicate_keys = [
55
56
        'execution_date', 'local_account', 'remote_account',
56
57
        'remote_owner', 'reference', 'message', 'transferred_amount'
126
127
        return [x for x in invoice.move_id.line_id if x.account_id.reconcile]
127
128
 
128
129
    def _match_debit_order(
129
 
        self, cr, uid, trans, account_info, log, context=None):
 
130
        self, cr, uid, trans, log, context=None):
130
131
 
131
132
        def is_zero(total):
132
133
            return self.pool.get('res.currency').is_zero(
133
 
                cr, uid, account_info.currency_id, total)
 
134
                cr, uid, trans.statement_id.currency_id, total)
134
135
 
135
136
        payment_order_obj = self.pool.get('payment.order')
136
137
        order_ids = payment_order_obj.search(
146
147
        if len(candidates) > 0:
147
148
            # retrieve the common account_id, if any
148
149
            account_id = False
149
 
            for order in candidates:
150
 
                for line in order.line_ids[0].debit_move_line_id.move_id.line_id:
151
 
                    if line.account_id.type == 'other':
152
 
                        if account_id and account_id != line.account_id.id:
153
 
                            account_id = False
154
 
                            break
155
 
                        else:
156
 
                            account_id = line.account_id.id
157
 
 
158
 
            # TODO at statement line confirm
159
 
            # this action generates a reconcile object
160
 
            # with all the payment order's move lines 
161
 
            # on the transfer account
162
 
            # reconcile_id = payment_order_obj.debit_reconcile_transfer(
163
 
            #    cr, uid, candidates[0].id, trans.transferred_amount, log, context)
164
 
            # if reconcile_id:
165
 
            # the move_line is only used for the account
166
 
            # and the reconcile_ids, so we return the first.
167
 
                return dict(
168
 
                    move_line_ids = False,
169
 
                    match_type = 'payment_order',
170
 
                    payment_order_ids = [x.id for x in candidates],
171
 
                    account_id = account_id,
172
 
                    partner_id = False,
173
 
                    partner_bank_id = False,
174
 
                    reference = False,
175
 
                    type='general',
176
 
                    )
 
150
            for line in candidate[0].line_ids[0].debit_move_line_id.move_id.line_id:
 
151
                if line.account_id.type == 'other':
 
152
                    account_id = line.account_id.id
 
153
                    break
 
154
            return dict(
 
155
                move_line_ids = False,
 
156
                match_type = 'payment_order',
 
157
                payment_order_ids = [x.id for x in candidates],
 
158
                account_id = account_id,
 
159
                partner_id = False,
 
160
                partner_bank_id = False,
 
161
                reference = False,
 
162
                type='general',
 
163
                )
177
164
        return False
178
165
 
179
166
    def _match_invoice(self, cr, uid, trans, move_lines,
180
 
                       partner_ids, bank_account_ids, log, linked_invoices,
 
167
                       partner_ids, bank_account_ids,
 
168
                       log, linked_invoices,
181
169
                       context=None):
182
170
        '''
183
171
        Find the invoice belonging to this reference - if there is one
277
265
 
278
266
        def is_zero(move_line, total):
279
267
            return self.pool.get('res.currency').is_zero(
280
 
                cr, uid, move_line.company_id.currency_id, total)
 
268
                cr, uid, trans.statement_id.currency, total)
281
269
 
282
270
        digits = dp.get_precision('Account')(cr)[1]
283
271
        partial = False
393
381
                    partial = False
394
382
                    # Last partial payment will not flag invoice paid without
395
383
                    # manual assistence
396
 
                    # TODO Stefan: disable this now for the interactive method
397
 
                    #   Solve this with proper handling of partial reconciliation 
 
384
                    # TODO Stefan: disable this here for the interactive method
 
385
                    #   Handled this with proper handling of partial reconciliation 
398
386
                    #   and the workflow service
399
387
                    # invoice_obj = self.pool.get('account.invoice')
400
388
                    # invoice_obj.write(cr, uid, [invoice.id], {
564
552
                            transaction.statement_line_id.statement_id.name,
565
553
                            transaction.statement_line_id.name
566
554
                     )))
567
 
        currency = (transaction.statement_line_id.statement_id.journal_id.currency or
568
 
                    transaction.statement_line_id.statement_id.company_id.currency_id)
 
555
        currency = transaction.statement_line_id.statement_id.currency
569
556
        line_ids = [transaction.move_line_id.id]
570
557
        if transaction.writeoff_move_line_id:
571
558
            line_ids.append(transaction.writeoff_move_line_id.id)
665
652
        statement_line_obj = self.pool.get('account.bank.statement.line')
666
653
        transaction = self.browse(cr, uid, transaction_id, context=context)
667
654
        move_line_id = transaction.move_line_id.id
668
 
        currency = (transaction.statement_line_id.statement_id.journal_id.currency or
669
 
                    transaction.statement_line_id.statement_id.company_id.currency_id)
 
655
        currency = transaction.statement_line_id.statement_id.currency
670
656
        line_ids = [transaction.move_line_id.id]
671
657
        if transaction.writeoff_move_line_id:
672
658
            line_ids.append(transaction.writeoff_move_line_id.id)
869
855
                cr, uid, [move_id], context=context)
870
856
 
871
857
    def _match_storno(
872
 
        self, cr, uid, trans, account_info, log, context=None):
 
858
        self, cr, uid, trans, log, context=None):
873
859
        payment_line_obj = self.pool.get('payment.line')
874
860
        move_line_obj = self.pool.get('account.move.line')
875
861
        line_ids = payment_line_obj.search(
882
868
        if len(line_ids) == 1:
883
869
            account_id = payment_line_obj.get_storno_account_id(
884
870
                cr, uid, line_ids[0], trans.transferred_amount,
885
 
                account_info.currency_id, context=None)
 
871
                trans.statement_id.currency, context=None)
886
872
            if account_id:
887
873
                return dict(
888
874
                    account_id = account_id,
1047
1033
        error_accounts = {}
1048
1034
        info = {}
1049
1035
        linked_payments = {}
1050
 
        # TODO: harvest linked invoices from draft statement lines
 
1036
        # TODO: harvest linked invoices from draft statement lines?
1051
1037
        linked_invoices = {}
1052
1038
        payment_lines = []
1053
1039
 
1055
1041
        # No filtering can be done, as empty dates carry value for C2B
1056
1042
        # communication. Most likely there are much less sent payments
1057
1043
        # than reconciled and open/draft payments.
1058
 
        # TODO: Don't payment_orders have a company nowadays?
 
1044
        # Strangely, payment_orders still do not have company_id
1059
1045
        cr.execute("SELECT l.id FROM payment_order o, payment_line l "
1060
1046
                       "WHERE l.order_id = o.id AND "
1061
1047
                       "o.state = 'sent' AND "
1072
1058
        i = 0
1073
1059
        max_trans = len(transactions)
1074
1060
        while i < max_trans:
1075
 
            move_info = False # TODO: this at statement_line confirmation time?
 
1061
            move_info = False
1076
1062
            if injected:
1077
1063
                # Force FIFO behavior
1078
1064
                transaction = injected.pop(0)
1079
1065
            else:
1080
1066
                transaction = transactions[i]
1081
1067
 
1082
 
            if transaction.statement_line_id:
1083
 
                # TODO check state
1084
 
                # and undo any reconciliation
1085
 
                pass
1086
 
 
 
1068
            if (transaction.statement_line_id and
 
1069
                transaction.statement_line_id.state == 'confirmed'):
 
1070
                raise osv.except_osv(
 
1071
                    _("Cannot perform match"),
 
1072
                    _("Cannot perform match on a confirmed transction"))
 
1073
            
1087
1074
            if transaction.local_account in error_accounts:
1088
1075
                results['trans_skipped_cnt'] += 1
1089
1076
                if not injected:
1228
1215
                transaction=self.browse(cr, uid, transaction.id, context=context)
1229
1216
            # Match full direct debit orders
1230
1217
            if transaction.type == bt.DIRECT_DEBIT:
1231
 
                move_info = self._match_debit_order( # TODO reconcile preservation
1232
 
                    cr, uid, transaction, account_info, results['log'], context)
 
1218
                move_info = self._match_debit_order(
 
1219
                    cr, uid, transaction, results['log'], context)
1233
1220
            if transaction.type == bt.STORNO:
1234
 
                move_info = self._match_storno( # TODO reconcile preservation
1235
 
                    cr, uid, transaction, account_info, results['log'], context)
 
1221
                move_info = self._match_storno(
 
1222
                    cr, uid, transaction, results['log'], context)
1236
1223
            # Allow inclusion of generated bank invoices
1237
1224
            if transaction.type == bt.BANK_COSTS:
1238
1225
                lines = self._match_costs(
1259
1246
                        country_code = iban.countrycode
1260
1247
                    elif transaction.remote_owner_country_code:
1261
1248
                        country_code = transaction.remote_owner_country_code
1262
 
                    # TODO: pass the parser's local country code to the transaction
1263
 
                    #  elif hasattr(parser, 'country_code') and parser.country_code:
1264
 
                    #      country_code = parser.country_code
1265
 
                    # For now, substituted by the company's country
 
1249
                    # fallback on the import parsers country code
 
1250
                    elif transaction.bank_country_code:
 
1251
                        country_code = transaction.bank_country_code
1266
1252
                    elif company.partner_id and company.partner_id.country:
1267
1253
                        country_code = company.partner_id.country.code
1268
1254
                    else:
1423
1409
                    wf_service.trg_validate(
1424
1410
                        uid, 'payment.order', id, 'done', cr)
1425
1411
 
1426
 
    column_map = {
1427
 
        'statement_id': 'statement',
1428
 
        'id': 'transaction'
1429
 
        }
1430
 
                
1431
1412
    def _get_residual(self, cr, uid, ids, name, args, context=None):
1432
1413
        """
1433
1414
        Calculate the residual against the candidate reconciliation.
1508
1489
        write_vals.update(vals or {})
1509
1490
        return self.write(cr, uid, ids, write_vals, context=context)
1510
1491
 
 
1492
    column_map = {
 
1493
        # used in bank_import.py, converting non-osv transactions
 
1494
        'statement_id': 'statement',
 
1495
        'id': 'transaction'
 
1496
        }
 
1497
                
1511
1498
    _columns = {
1512
1499
        # start mem_bank_transaction atributes
1513
1500
        # see parsers/models.py
1542
1529
        'provision_costs_description': fields.char('provision_costs_description', size=24),
1543
1530
        'error_message': fields.char('error_message', size=1024),
1544
1531
        'storno_retry': fields.boolean('storno_retry'),
1545
 
 
1546
1532
        # end of mem_bank_transaction_fields
 
1533
        'bank_country_code': fields.char(
 
1534
            'Bank country code', size=2,
 
1535
            help=("Fallback default country for new partner records, "
 
1536
                  "as defined by the import parser"),
 
1537
            readonly=True,),
1547
1538
        'company_id': fields.many2one(
1548
1539
            'res.company', 'Company', required=True),
1549
1540
        'duplicate': fields.boolean('duplicate'),
1747
1738
 
1748
1739
    def _end_balance(self, cursor, user, ids, name, attr, context=None):
1749
1740
        """
1750
 
        This method taken from account/account_bank_statement.py
1751
 
        to take the statement line subflow into account
 
1741
        This method taken from account/account_bank_statement.py and
 
1742
        altered to take the statement line subflow into account
1752
1743
        """
1753
1744
 
1754
1745
        res_currency_obj = self.pool.get('res.currency')