35
34
'state': fields.selection([('total', 'Full Reconciliation'), ('partial', 'Partial Reconciliation'),
36
35
('total_change', 'Full Reconciliation with change'), ('partial_change', 'Partial Reconciliation with change')], string="State",
37
36
required=True, readonly=True),
38
'different_currencies': fields.boolean('Is this reconciliation in different currencies? (2 at most)'),
42
40
'state': lambda *a: 'total',
43
'different_currencies': lambda *a: False,
46
43
def default_get(self, cr, uid, fields, context=None):
89
83
intermission_default_account_id = False
90
84
if self.pool.get('res.users').browse(cr, uid, uid).company_id.intermission_default_counterpart:
91
85
intermission_default_account_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.intermission_default_counterpart.id
92
# Browse all lines and check currencies, journals, and transfers state
93
currencies = defaultdict(list)
94
journals = defaultdict(list)
96
transfer_with_change = False
97
disregard_third_party = False
102
87
for line in account_move_line_obj.browse(cr, uid, context['active_ids']):
103
88
if line.move_id and line.move_id.state == 'posted':
104
# Prepare some infos needed for transfers with/without change
105
currencies[(line.currency_id, line.transfer_journal_id and line.transfer_journal_id.currency or None)].append(line.id)
106
journals[(line.journal_id.id, line.transfer_journal_id and line.transfer_journal_id.id or None)].append(line.id)
107
if line.is_transfer_with_change:
108
transfers.append(line.id)
109
if line.account_id.type_for_register == 'disregard_rec':
110
disregard_third_party = True
112
credits += line.credit
113
statements.append(line.statement_id)
115
90
raise osv.except_osv(_('Warning'), _('You can only do reconciliation on Posted Entries!'))
116
# Check lines for transfers cases (this permit to do transfers with more than 2 lines!)
117
if len(journals) == 2:
118
keys = journals.keys()
119
# Cross check on: "third parties" × "journals" (if YES, this is a transfer)
120
if keys[0][1] == keys[1][0] and keys[0][0] == keys[1][1]:
122
if len(transfers) == len(context['active_ids']):
123
transfer_with_change = True
124
# Cross check on: "journal currency" × "transfer_journal currency" (should check all error cases to avoid transfer_with_change problems)
125
if transfer_with_change:
126
keys_c = currencies.keys()
127
if len(currencies) != 2 or keys_c[0][1] != keys_c[1][0] or keys_c[0][0] != keys_c[1][1]:
128
transfer_with_change = False
129
# UTP-526: Do not raise next error if line comes from the same register and have same amount
132
for st in statements:
136
if st != previous_st:
139
if not (same and debits == credits):
140
raise osv.except_osv(_('Warning'), _("Cannot reconcile entries : Cross check between transfer currencies fails."))
141
91
prev_acc_id = None
142
92
prev_third_party = None
94
transfer_with_change = False
95
# Transfer verification
97
if len(context['active_ids']) == 1:
99
search_ids = account_move_line_obj.search(cr, uid, [('account_id.type_for_register', 'in', ['transfer_same', 'transfer']),
100
('id', operator, context['active_ids'])], context=context)
101
if len(context['active_ids']) == len(search_ids):
102
if len(context['active_ids']) == 2:
103
elements = account_move_line_obj.browse(cr, uid, context['active_ids'], context)
104
first_line = elements[0]
105
second_line = elements[1]
106
if first_line.journal_id and first_line.transfer_journal_id and second_line.journal_id and second_line.transfer_journal_id:
107
# Cross check on third parties
108
if first_line.journal_id.id == second_line.transfer_journal_id.id and second_line.journal_id.id == first_line.transfer_journal_id.id:
110
# Cross check on currencies for transfer_with_change verification
111
if first_line.is_transfer_with_change and second_line.is_transfer_with_change:
112
if first_line.journal_id.currency == second_line.transfer_journal_id.currency and first_line.transfer_journal_id.currency == second_line.journal_id.currency:
113
transfer_with_change = True
115
raise osv.except_osv(_('Warning'), _("Cannot reconcile entries : Cross check between transfer currencies fails."))
143
116
if transfer_with_change:
144
117
# For transfer with change, we need to do a total reconciliation!
145
118
state = 'total_change'
148
119
for line in account_move_line_obj.browse(cr, uid, context['active_ids'], context=context):
149
120
# prepare some values
150
121
account_id = line.account_id.id
151
122
# some verifications
152
123
if not line.account_id.reconcile:
153
124
raise osv.except_osv(_('Warning'), _('This account is not reconciliable: %s') % (line.account_id.code,))
154
# Check that currency id is the same unless transfer with change cases
156
currency_id = line.currency_id and line.currency_id.id or False
157
if line.currency_id and line.currency_id.id != currency_id and not transfer_with_change:
158
currency2_id = line.currency_id.id
159
125
# verification that there's only one account for each line
160
126
if not prev_acc_id:
161
127
prev_acc_id = account_id
163
129
raise osv.except_osv(_('Error'), _('An account is different from others: %s') % (line.account_id.code,))
164
130
# verification that there's only one 3rd party
165
131
# The 3rd party verification is desactivated in case of transfer with change
166
# UTP-1040: 3RD party is also desactivated in case of account that is "Disregard Third Party" as "type_for_register"
167
if not transfer and not disregard_third_party:
169
134
'partner_id': line.partner_id and line.partner_id.id or False,
170
135
'employee_id': line.employee_id and line.employee_id.id or False,
136
'register_id': line.register_id and line.register_id.id or False,
171
137
'transfer_journal_id': line.transfer_journal_id and line.transfer_journal_id.id or False}
172
138
if not prev_third_party:
173
139
prev_third_party = third_party
174
140
if prev_third_party != third_party:
175
141
# Do not raise an exception if salary_default_account is configured and this line account is equal to default salary account
176
# True + not (False + False) => True [ERROR message]
177
# True + not (True + False) or True + not (False + True) => True [ERROR message]
178
# True + not (True + True) => False [NO error]
179
# False + anything => False [NO error]
180
if line.account_id.id != salary_account_id and not (line.partner_id.partner_type == 'intermission' and line.account_id.id != intermission_default_account_id):
181
raise osv.except_osv(_('Error'), _('Third parties do not match or bad company configuration!'))
142
if line.account_id.id != salary_account_id and (line.partner_id.partner_type == 'intermission' and line.account_id.id != intermission_default_account_id):
143
raise osv.except_osv(_('Error'), _('A third party is different from others: %s') % line.partner_txt)
182
144
# process necessary elements
183
145
if not line.reconcile_id and not line.reconcile_id.id:
185
147
credit += line.credit_currency
186
148
debit += line.debit_currency
187
fcredit += line.credit
149
if transfer_with_change:
150
fcredit += line.credit
189
152
# Adapt state value
190
153
if (debit - credit) == 0.0:
195
158
if (fdebit - fcredit) == 0.0:
196
159
state = 'total_change'
198
different_currencies = False
199
if currency_id and currency2_id and not transfer_with_change:
200
different_currencies = True
203
160
# For salaries, behaviour is the same as total_change: we use functional debit/credit
204
if account_id == salary_account_id or (currency_id and currency2_id and not transfer_with_change):
161
if account_id == salary_account_id:
205
162
if (fdebit - fcredit) == 0.0:
208
165
state = 'partial'
209
# UF-2050: Do not allow partial reconciliation of entries in different currencies. We ALWAYS do total reconciliation
210
if different_currencies and not transfer_with_change:
212
return {'trans_nbr': count, 'account_id': account_id, 'credit': credit, 'debit': debit, 'writeoff': debit - credit, 'state': state, 'different_currencies': different_currencies}
166
return {'trans_nbr': count, 'account_id': account_id, 'credit': credit, 'debit': debit, 'writeoff': debit - credit, 'state': state}
214
168
def total_reconcile(self, cr, uid, ids, context=None):