Merge lp:~julie-w/unifield-server/US-8896 into lp:unifield-server
- US-8896
- Merge into trunk
Proposed by
jftempo
Status: | Merged |
---|---|
Merged at revision: | 6155 |
Proposed branch: | lp:~julie-w/unifield-server/US-8896 |
Merge into: | lp:unifield-server |
Diff against target: |
629 lines (+176/-82) 14 files modified
bin/addons/account/account_invoice_view.xml (+7/-2) bin/addons/account/invoice.py (+5/-1) bin/addons/account/report/export_invoice.mako (+1/-1) bin/addons/account/report/invoice_excel_export.mako (+1/-1) bin/addons/account_override/account_invoice_sync.py (+61/-18) bin/addons/account_override/account_invoice_view.xml (+6/-20) bin/addons/account_override/invoice.py (+16/-3) bin/addons/account_override/report/allocation_invoices_report.rml (+1/-1) bin/addons/account_override/report/report_allocation_invoices.py (+30/-6) bin/addons/analytic_distribution/analytic_distribution.py (+2/-2) bin/addons/analytic_distribution/invoice.py (+1/-1) bin/addons/msf_profile/i18n/fr_MF.po (+22/-24) bin/addons/register_accounting/account_invoice_view.xml (+8/-2) bin/addons/register_accounting/invoice.py (+15/-0) |
To merge this branch: | bzr merge lp:~julie-w/unifield-server/US-8896 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+413758@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/addons/account/account_invoice_view.xml' |
2 | --- bin/addons/account/account_invoice_view.xml 2022-01-05 16:30:54 +0000 |
3 | +++ bin/addons/account/account_invoice_view.xml 2022-01-06 16:20:57 +0000 |
4 | @@ -83,7 +83,10 @@ |
5 | <field name="discount" groups="base.group_extended" |
6 | attrs="{'readonly': [('invoice_type', '=', 'in_invoice'), ('line_synced', '=', True)]}"/> |
7 | <field colspan="4" name="name"/> |
8 | - <field domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '<>', 'view')]" name="account_id"/> |
9 | + <field name="account_id" |
10 | + domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('restricted_area', '=', 'invoice_lines')]" |
11 | + required="1" |
12 | + /> |
13 | <field domain="[('type','<>','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" name="account_analytic_id" groups="analytic.group_analytic_accounting"/> |
14 | <newline/> |
15 | <field name="company_id" groups="base.group_multi_company" readonly="1"/> |
16 | @@ -236,7 +239,7 @@ |
17 | </group> |
18 | |
19 | <field colspan="4" default_get="{'check_total': check_total, 'invoice_line': invoice_line, 'address_invoice_id': address_invoice_id, 'partner_id': partner_id, 'price_type': 'price_type' in dir() and price_type or False}" name="invoice_line" nolabel="1"> |
20 | - <tree string="Invoice lines" editable="both" colors="red:analytic_distribution_state in ('invalid', 'invalid_small_amount') or inactive_product == True;black:analytic_distribution_state in ('none','valid') and inactive_product == False"> |
21 | + <tree string="Invoice lines" editable="both" colors="red:analytic_distribution_state in ('invalid', 'invalid_small_amount') or inactive_product == True or not account_id;black:analytic_distribution_state in ('none', 'valid') and inactive_product == False and account_id"> |
22 | <field name="from_supply" invisible="1"/> |
23 | <field name="line_synced" invisible="1"/> |
24 | <field name="invoice_type" invisible="1"/> |
25 | @@ -252,6 +255,7 @@ |
26 | /> |
27 | <field name="account_id" |
28 | domain="[('journal_id', '=', parent.journal_id), ('restricted_area', '=', 'invoice_lines')]" |
29 | + required="1" |
30 | /> |
31 | <field name="invoice_line_tax_id" view_mode="2" context="{'type':parent.type}" domain="[('parent_id','=',False)]"/> |
32 | <field name="inactive_product" invisible="1" /> |
33 | @@ -489,6 +493,7 @@ |
34 | /> |
35 | <field name="account_id" |
36 | domain="[('journal_id', '=', parent.journal_id), ('restricted_area', '=', 'invoice_lines')]" |
37 | + required="1" |
38 | context="{'type': parent.type, 'journal_type': parent.journal_type}" |
39 | /> |
40 | <button name="button_analytic_distribution" string="Analytical Distribution" type="object" |
41 | |
42 | === modified file 'bin/addons/account/invoice.py' |
43 | --- bin/addons/account/invoice.py 2022-01-05 16:25:16 +0000 |
44 | +++ bin/addons/account/invoice.py 2022-01-06 16:20:57 +0000 |
45 | @@ -1338,6 +1338,9 @@ |
46 | if 'analytic_line_ids' in line: |
47 | line['analytic_line_ids'] = False |
48 | |
49 | + if 'allow_no_account' in line: |
50 | + line['allow_no_account'] = False |
51 | + |
52 | for field in ( |
53 | 'company_id', 'partner_id', 'account_id', 'product_id', |
54 | 'uos_id', 'account_analytic_id', 'tax_code_id', 'base_code_id','account_tax_id', |
55 | @@ -1660,7 +1663,8 @@ |
56 | selection=PARTNER_TYPE, readonly=True, store=False), |
57 | 'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'), |
58 | 'product_id': fields.many2one('product.product', 'Product', ondelete='set null'), |
59 | - 'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."), |
60 | + 'account_id': fields.many2one('account.account', 'Account', domain=[('type', '<>', 'view'), ('type', '<>', 'closed')], |
61 | + help="The income or expense account related to the selected product."), |
62 | 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Account')), |
63 | 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal', type="float", |
64 | digits_compute= dp.get_precision('Account'), store=True), |
65 | |
66 | === modified file 'bin/addons/account/report/export_invoice.mako' |
67 | --- bin/addons/account/report/export_invoice.mako 2021-04-28 14:17:59 +0000 |
68 | +++ bin/addons/account/report/export_invoice.mako 2022-01-06 16:20:57 +0000 |
69 | @@ -145,7 +145,7 @@ |
70 | % endif |
71 | <Data ss:Type="String">${inv_line.product_id and inv_line.product_id.default_code or ''|x}</Data></Cell> |
72 | |
73 | - <Cell ss:StyleID="editable"><Data ss:Type="String">${inv_line.account_id.code|x}</Data></Cell> |
74 | + <Cell ss:StyleID="editable"><Data ss:Type="String">${inv_line.account_id and inv_line.account_id.code or ''|x}</Data></Cell> |
75 | |
76 | % if is_ro: |
77 | <Cell ss:StyleID="non_editable_number"> |
78 | |
79 | === modified file 'bin/addons/account/report/invoice_excel_export.mako' |
80 | --- bin/addons/account/report/invoice_excel_export.mako 2020-04-14 16:07:03 +0000 |
81 | +++ bin/addons/account/report/invoice_excel_export.mako 2022-01-06 16:20:57 +0000 |
82 | @@ -115,7 +115,7 @@ |
83 | <Cell ss:StyleID="line_number"><Data ss:Type="Number">${distrib_line['percentage']|x}</Data></Cell> |
84 | <Cell ss:StyleID="line_number"><Data ss:Type="Number">${inv_line.price_unit|x}</Data></Cell> |
85 | <Cell ss:StyleID="line_number"><Data ss:Type="Number">${distrib_line['subtotal']|x}</Data></Cell> |
86 | - <Cell ss:StyleID="line"><Data ss:Type="String">${inv_line.account_id.code|x}</Data></Cell> |
87 | + <Cell ss:StyleID="line"><Data ss:Type="String">${inv_line.account_id and inv_line.account_id.code or ''|x}</Data></Cell> |
88 | <Cell ss:StyleID="line"><Data ss:Type="String">${distrib_line['cost_center']|x}</Data></Cell> |
89 | <Cell ss:StyleID="line"><Data ss:Type="String">${distrib_line['destination']|x}</Data></Cell> |
90 | <Cell ss:StyleID="line"><Data ss:Type="String">${inv_line.invoice_id.number or ''|x}</Data></Cell> |
91 | |
92 | === modified file 'bin/addons/account_override/account_invoice_sync.py' |
93 | --- bin/addons/account_override/account_invoice_sync.py 2021-10-18 08:18:07 +0000 |
94 | +++ bin/addons/account_override/account_invoice_sync.py 2022-01-06 16:20:57 +0000 |
95 | @@ -84,6 +84,21 @@ |
96 | fp_distrib_line_obj.create(cr, uid, distrib_vals, context=context) |
97 | vals.update({'analytic_distribution_id': distrib_id,}) |
98 | |
99 | + def _set_partially_run(self, line_name, partially_run_msg, new_msg, context): |
100 | + """ |
101 | + Sets the invoices in Partially (Not) Run: |
102 | + - updates contexts accordingly |
103 | + - updates the partially_run_msg with the new_msg |
104 | + - at line level sets the account to False and the tag allow_no_account to True |
105 | + """ |
106 | + context['partial_sync_run'] = True |
107 | + line_account_id = False |
108 | + allow_no_account = True |
109 | + if partially_run_msg: |
110 | + partially_run_msg += "\n" |
111 | + partially_run_msg += 'Line "%s": %s' % (line_name, new_msg) |
112 | + return line_account_id, allow_no_account, partially_run_msg |
113 | + |
114 | def _create_invoice_lines(self, cr, uid, inv_lines_data, inv_id, inv_posting_date, inv_linked_po, from_supply, context=None): |
115 | """ |
116 | Creates the lines of the automatic counterpart invoice (inv_id) generated at synchro time. |
117 | @@ -96,7 +111,9 @@ |
118 | product_uom_obj = self.pool.get('product.uom') |
119 | inv_line_obj = self.pool.get('account.invoice.line') |
120 | pol_obj = self.pool.get('purchase.order.line') |
121 | + partially_run_msg = "" |
122 | for inv_line in inv_lines_data: |
123 | + allow_no_account = False |
124 | line_name = inv_line.get('name', '') |
125 | if not line_name: # required field |
126 | raise osv.except_osv(_('Error'), _("Impossible to retrieve the line description.")) |
127 | @@ -153,22 +170,51 @@ |
128 | elif not line_account_id: |
129 | account_code = inv_line.get('account_id', {}).get('code', '') |
130 | if not account_code: |
131 | - raise osv.except_osv(_('Error'), _("Impossible to retrieve the account code at line level.")) |
132 | - account_ids = account_obj.search(cr, uid, [('code', '=', account_code)], limit=1, context=context) |
133 | - if not account_ids: |
134 | - raise osv.except_osv(_('Error'), _("Account code %s not found.") % account_code) |
135 | - line_account_id = account_ids[0] |
136 | - if not line_account_id: |
137 | - raise osv.except_osv(_('Error'), _("Error when retrieving the account at line level.")) |
138 | - line_account = account_obj.browse(cr, uid, line_account_id, |
139 | - fields_to_fetch=['activation_date', 'inactivation_date'], context=context) |
140 | - if inv_posting_date < line_account.activation_date or \ |
141 | - (line_account.inactivation_date and inv_posting_date >= line_account.inactivation_date): |
142 | - raise osv.except_osv(_('Error'), _('The account "%s - %s" is inactive.') % (line_account.code, line_account.name)) |
143 | - inv_line_vals.update({'account_id': line_account_id, |
144 | + new_msg = "Impossible to retrieve the account code." |
145 | + line_account_id, allow_no_account, partially_run_msg = self._set_partially_run(line_name, |
146 | + partially_run_msg, |
147 | + new_msg, context) |
148 | + else: |
149 | + account_ids = account_obj.search(cr, uid, [('code', '=', account_code)], limit=1, context=context) |
150 | + if not account_ids: |
151 | + new_msg = "Account %s not found." % (account_code,) |
152 | + line_account_id, allow_no_account, partially_run_msg = self._set_partially_run(line_name, partially_run_msg, |
153 | + new_msg, context) |
154 | + else: |
155 | + line_account_id = account_ids[0] |
156 | + if not line_account_id and not allow_no_account: |
157 | + new_msg = "Error when retrieving the account." |
158 | + line_account_id, allow_no_account, partially_run_msg = self._set_partially_run(line_name, partially_run_msg, new_msg, context) |
159 | + if line_account_id: |
160 | + line_account = account_obj.browse(cr, uid, line_account_id, |
161 | + fields_to_fetch=['activation_date', 'inactivation_date', 'code'], context=context) |
162 | + if inv_posting_date < line_account.activation_date or \ |
163 | + (line_account.inactivation_date and inv_posting_date >= line_account.inactivation_date): |
164 | + new_msg = "Account %s inactive." % (line_account.code,) |
165 | + line_account_id, allow_no_account, partially_run_msg = self._set_partially_run(line_name, partially_run_msg, |
166 | + new_msg, context) |
167 | + inv_line_vals.update({'account_id': line_account_id or False, |
168 | + 'allow_no_account': allow_no_account, |
169 | 'product_id': product_id, |
170 | }) |
171 | inv_line_obj.create(cr, uid, inv_line_vals, context=context) |
172 | + return partially_run_msg |
173 | + |
174 | + def _get_msg(self, journal_type, partially_run_msg, inv_id): |
175 | + """ |
176 | + Returns the message to be printed in the Messages Received |
177 | + """ |
178 | + if journal_type == 'sale': |
179 | + msg_prefix = 'The ISI No.' |
180 | + elif journal_type == 'intermission': |
181 | + msg_prefix = 'The IVI No.' |
182 | + else: |
183 | + msg_prefix = 'The Invoice No.' |
184 | + if partially_run_msg: |
185 | + msg_suffix = "is Partially Not Run.\n\n%s" % partially_run_msg |
186 | + else: |
187 | + msg_suffix = "has been created successfully." |
188 | + return "%s %s %s" % (msg_prefix, inv_id, msg_suffix) |
189 | |
190 | def create_invoice_from_sync(self, cr, uid, source, invoice_data, context=None): |
191 | """ |
192 | @@ -323,11 +369,8 @@ |
193 | ) |
194 | inv_id = self.create(cr, uid, vals, context=context) |
195 | if inv_id: |
196 | - self._create_invoice_lines(cr, uid, inv_lines, inv_id, posting_date, po, from_supply, context=context) |
197 | - if journal_type == 'sale': |
198 | - msg = "ISI No. %s created successfully." % inv_id |
199 | - elif journal_type == 'intermission': |
200 | - msg = "IVI No. %s created successfully." % inv_id |
201 | + partially_run_msg = self._create_invoice_lines(cr, uid, inv_lines, inv_id, posting_date, po, from_supply, context=context) |
202 | + msg = self._get_msg(journal_type, partially_run_msg, inv_id) |
203 | self._logger.info(msg) |
204 | return msg |
205 | |
206 | |
207 | === modified file 'bin/addons/account_override/account_invoice_view.xml' |
208 | --- bin/addons/account_override/account_invoice_view.xml 2022-01-05 16:28:33 +0000 |
209 | +++ bin/addons/account_override/account_invoice_view.xml 2022-01-06 16:20:57 +0000 |
210 | @@ -28,21 +28,6 @@ |
211 | </record> |
212 | |
213 | |
214 | - <!-- Change account_id domain --> |
215 | - <record id="invoice_line_form3" model="ir.ui.view"> |
216 | - <field name="name">account.invoice.line.form</field> |
217 | - <field name="model">account.invoice.line</field> |
218 | - <field name="type">form</field> |
219 | - <field name="priority" eval="20"/> |
220 | - <field name="inherit_id" ref="account.view_invoice_line_form"/> |
221 | - <field name="arch" type="xml"> |
222 | - <xpath expr="//field[@name='account_id']" position="attributes"> |
223 | - <attribute name="domain">[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('restricted_area', '=', 'invoice_lines')]</attribute> |
224 | - </xpath> |
225 | - </field> |
226 | - </record> |
227 | - |
228 | - |
229 | <!-- |
230 | Debit Note views |
231 | --> |
232 | @@ -104,7 +89,7 @@ |
233 | <field colspan="4" name="invoice_line" nolabel="1" widget="one2many_list"> |
234 | <tree editable="top" string="Invoice Line" noteditable="1" hide_new_button="1"> |
235 | <field name="name"/> |
236 | - <field name="account_id" domain="[('restricted_area', '=', 'invoice_lines')]"/> |
237 | + <field name="account_id" domain="[('restricted_area', '=', 'invoice_lines')]" required="1"/> |
238 | <field name="quantity"/> |
239 | <field name="uos_id" string="UoM"/> |
240 | <field name="price_unit"/> |
241 | @@ -236,7 +221,7 @@ |
242 | attrs="{'readonly': [('from_supply', '=', True)]}" |
243 | on_change="onchange_donation_product(product_id, quantity, parent.currency_id, context)" |
244 | /> |
245 | - <field name="account_id" domain="[('restricted_area', '=', 'donation_lines')]"/> |
246 | + <field name="account_id" domain="[('restricted_area', '=', 'donation_lines')]" required="1"/> |
247 | <button name="button_analytic_distribution" string="Analytical Distribution" type="object" icon="terp-stock_symbol-selection" |
248 | context="{'d_journal_id': parent.journal_id , 'd_partner_id': parent.partner_id, 'd_address_invoice_id':parent.address_invoice_id,'d_date_invoice': parent.date_invoice, 'd_register_posting_date': parent.register_posting_date, 'd_account_id': parent.account_id, 'd_partner_bank_id': parent.partner_bank_id, 'd_payment_term': parent.payment_term, 'd_name': parent.name, 'd_origine': parent.origin, 'd_address_contact_id': parent.address_contact_id, 'd_user_id': parent.user_id, 'd_comment': parent.comment}" |
249 | /> |
250 | @@ -260,7 +245,7 @@ |
251 | on_change="onchange_donation_product(product_id, quantity, parent.currency_id, context)" |
252 | default_focus="1" |
253 | /> |
254 | - <field name="account_id" domain="[('restricted_area', '=', 'donation_lines')]"/> |
255 | + <field name="account_id" domain="[('restricted_area', '=', 'donation_lines')]" required="1"/> |
256 | <field name="name" colspan="4" /> |
257 | <field name="quantity" |
258 | attrs="{'readonly': [('from_supply', '=', True)]}" |
259 | @@ -405,7 +390,7 @@ |
260 | <field colspan="4" name="invoice_line" nolabel="1" widget="one2many_list" context="{'is_intermission': True, 'from_inv_form': True}"> |
261 | <tree string="Intermission Voucher Lines" |
262 | editable="both" |
263 | - colors="red:analytic_distribution_state in ('invalid', 'invalid_small_amount') or inactive_product == True;black:inactive_product == False and analytic_distribution_state in ('none', 'valid')"> |
264 | + colors="red:analytic_distribution_state in ('invalid', 'invalid_small_amount') or inactive_product == True or not account_id;black:inactive_product == False and analytic_distribution_state in ('none', 'valid') and account_id"> |
265 | <field name="from_supply" invisible="1"/> |
266 | <field name="line_synced" invisible="1"/> |
267 | <field name="invoice_type" invisible="1"/> |
268 | @@ -418,6 +403,7 @@ |
269 | ('from_supply', '=', True), |
270 | '&', ('invoice_type', '=', 'in_invoice'), ('line_synced', '=', True)]}" /> |
271 | <field name="account_id" domain="[('restricted_area', '=', 'intermission_lines')]" |
272 | + required="1" |
273 | context="{'type': parent.type, 'journal_type': parent.journal_type, 'intermission_type': parent.type == 'out_invoice' and 'out' or 'in'}" |
274 | /> |
275 | <button name="button_analytic_distribution" string="Analytical Distribution" type="object" icon="terp-stock_symbol-selection" |
276 | @@ -468,7 +454,7 @@ |
277 | <field name="price_unit" attrs="{'readonly': [('invoice_type', '=', 'in_invoice'), ('line_synced', '=', True)]}"/> |
278 | <field name="discount" groups="base.group_extended" attrs="{'readonly': [('invoice_type', '=', 'in_invoice'), ('line_synced', '=', True)]}"/> |
279 | <field name="name" colspan="4"/> |
280 | - <field name="account_id" domain="[('restricted_area', '=', 'intermission_lines')]"/> |
281 | + <field name="account_id" domain="[('restricted_area', '=', 'intermission_lines')]" required="1"/> |
282 | <group colspan="6"> |
283 | <field name="analytic_distribution_state" invisible="1"/> |
284 | <field name="newline" invisible="1" /> |
285 | |
286 | === modified file 'bin/addons/account_override/invoice.py' |
287 | --- bin/addons/account_override/invoice.py 2022-01-05 16:30:54 +0000 |
288 | +++ bin/addons/account_override/invoice.py 2022-01-06 16:20:57 +0000 |
289 | @@ -1640,6 +1640,7 @@ |
290 | # - an invoice line can be linked to several CV lines => e.g. merge invoice lines by account |
291 | 'cv_line_ids': fields.many2many('account.commitment.line', 'inv_line_cv_line_rel', 'inv_line_id', 'cv_line_id', |
292 | string='Commitment Voucher Lines'), |
293 | + 'allow_no_account': fields.boolean(string='Allow an empty account on the line', readonly=True), |
294 | } |
295 | |
296 | _defaults = { |
297 | @@ -1647,10 +1648,16 @@ |
298 | 'is_corrected': lambda *a: False, |
299 | 'vat_ok': lambda obj, cr, uid, context: obj.pool.get('unifield.setup.configuration').get_config(cr, uid).vat_ok, |
300 | 'merged_line': lambda *a: False, |
301 | + 'allow_no_account': lambda *a: False, |
302 | } |
303 | |
304 | _order = 'line_number' |
305 | |
306 | + _sql_constraints = [ |
307 | + ('ck_invl_account', "CHECK(account_id IS NOT NULL OR COALESCE(allow_no_account, 'f') = 't')", |
308 | + 'The invoice lines must have an account.') |
309 | + ] |
310 | + |
311 | def _check_on_invoice_line_big_amounts(self, cr, uid, ids, context=None): |
312 | """ |
313 | Prevents booking amounts having more than 10 digits before the comma, i.e. amounts starting from 10 billions. |
314 | @@ -1782,20 +1789,26 @@ |
315 | |
316 | return new_id |
317 | |
318 | - def copy_data(self, cr, uid, inv_id, default=None, context=None): |
319 | + def copy_data(self, cr, uid, invl_id, default=None, context=None): |
320 | """ |
321 | Copy an invoice line without its move lines, |
322 | without the link to a reversed invoice line, |
323 | and without link to PO/FO/CV lines when the duplication is manual |
324 | - Reset the merged_line tag. |
325 | + Reset the merged_line and allow_no_account tags. |
326 | + Prevent the manual duplication of invoices lines with no account. |
327 | """ |
328 | if context is None: |
329 | context = {} |
330 | if default is None: |
331 | default = {} |
332 | + # The only way to get invoice lines without account should be via synchro and not via duplication |
333 | + # (display a specific error message instead of the SQL error) |
334 | + if context.get('from_copy_web') and not self.read(cr, uid, invl_id, ['account_id'], context=context)['account_id']: |
335 | + raise osv.except_osv(_('Warning'), _("Duplication not allowed. Please set an account on all lines first.")) |
336 | default.update({'move_lines': False, |
337 | 'reversed_invoice_line_id': False, |
338 | 'merged_line': False, |
339 | + 'allow_no_account': False, |
340 | }) |
341 | # Manual duplication should generate a "manual document not created through the supply workflow" |
342 | # so we don't keep the link to PO/FO/CV at line level |
343 | @@ -1807,7 +1820,7 @@ |
344 | 'purchase_order_line_ids': [], |
345 | 'cv_line_ids': [(6, 0, [])], |
346 | }) |
347 | - return super(account_invoice_line, self).copy_data(cr, uid, inv_id, default, context) |
348 | + return super(account_invoice_line, self).copy_data(cr, uid, invl_id, default, context) |
349 | |
350 | def unlink(self, cr, uid, ids, context=None): |
351 | """ |
352 | |
353 | === modified file 'bin/addons/account_override/report/allocation_invoices_report.rml' |
354 | --- bin/addons/account_override/report/allocation_invoices_report.rml 2016-04-29 14:08:12 +0000 |
355 | +++ bin/addons/account_override/report/allocation_invoices_report.rml 2022-01-06 16:20:57 +0000 |
356 | @@ -88,7 +88,7 @@ |
357 | <para style="Information">[[ o.partner_id.name ]]</para> |
358 | </td> |
359 | <td> |
360 | - <para style="Information">[[ getSel(o, 'type') ]]</para> |
361 | + <para style="Information">[[ get_doc_type(o) ]]</para> |
362 | </td> |
363 | <td> |
364 | <para style="Information">[[ get_journal_code(o) ]]</para> |
365 | |
366 | === modified file 'bin/addons/account_override/report/report_allocation_invoices.py' |
367 | --- bin/addons/account_override/report/report_allocation_invoices.py 2017-08-09 13:31:11 +0000 |
368 | +++ bin/addons/account_override/report/report_allocation_invoices.py 2022-01-06 16:20:57 +0000 |
369 | @@ -34,6 +34,7 @@ |
370 | 'time': time, |
371 | 'get_data': self.get_data, |
372 | 'get_total_amount': self.get_total_amount, |
373 | + 'get_doc_type': self.get_doc_type, |
374 | 'get_journal_code': self.get_journal_code, |
375 | }) |
376 | |
377 | @@ -45,6 +46,7 @@ |
378 | - an AD defined at line level (first SELECT) |
379 | - an AD defined at header level (second SELECT) |
380 | - no AD (third SELECT) |
381 | + - no account - in that case the AD is seen as empty (fourth SELECT) |
382 | """ |
383 | self._cr.execute("""SELECT line_number,NULLIF('[' || default_code || '] ' || name_template, '[] ') as product,i.name as description, ac.code || ' ' || ac.name as account, quantity, ROUND(price_unit, 2) as price_unit, ROUND(percentage, 2) as percentage, ROUND(price_subtotal*percentage/100, 2) as sub_total, y.name as currency, n1.code as destination, n2.code as cost_center, n3.code as funding_pool |
384 | FROM funding_pool_distribution_line a |
385 | @@ -56,7 +58,7 @@ |
386 | INNER JOIN account_account ac ON ac.id = i.account_id |
387 | LEFT JOIN product_product p ON p.id = i.product_id |
388 | LEFT JOIN res_currency y ON y.id = s.currency_id |
389 | - WHERE i.invoice_id=%s |
390 | + WHERE i.invoice_id=%s AND i.account_id IS NOT NULL AND ac.is_analytic_addicted = True |
391 | UNION ALL |
392 | SELECT line_number,NULLIF('[' || default_code || '] ' || name_template, '[] ') as product,i.name as description, ac.code || ' ' || ac.name as account, quantity, ROUND(price_unit, 2) as price_unit, ROUND(percentage, 2) as percentage, ROUND(price_subtotal*percentage/100, 2) as sub_total, y.name as currency, n1.code as destination, n2.code as cost_center, n3.code as funding_pool |
393 | FROM funding_pool_distribution_line a |
394 | @@ -68,7 +70,7 @@ |
395 | INNER JOIN account_analytic_account n3 ON n3.id = a.analytic_id |
396 | INNER JOIN res_currency y ON y.id = s.currency_id |
397 | LEFT JOIN product_product p ON p.id = i.product_id |
398 | - WHERE s.id=%s AND ac.is_analytic_addicted = True |
399 | + WHERE s.id=%s AND i.account_id IS NOT NULL AND ac.is_analytic_addicted = True |
400 | UNION ALL |
401 | SELECT line_number, NULLIF('[' || default_code || '] ' || name_template, '[] ') as product, i.name as description, |
402 | ac.code || ' ' || ac.name as account, quantity, ROUND(price_unit, 2) as price_unit, NULL, |
403 | @@ -78,9 +80,18 @@ |
404 | INNER JOIN account_account ac ON ac.id = i.account_id |
405 | INNER JOIN res_currency y ON y.id = s.currency_id |
406 | LEFT JOIN product_product p ON p.id = i.product_id |
407 | - WHERE s.id=%s and is_analytic_addicted = False |
408 | + WHERE s.id=%s AND i.account_id IS NOT NULL AND is_analytic_addicted = False |
409 | + UNION ALL |
410 | + SELECT line_number, NULLIF('[' || default_code || '] ' || name_template, '[] ') as product, i.name as description, |
411 | + '' as account, quantity, ROUND(price_unit, 2) as price_unit, NULL, |
412 | + ROUND(price_subtotal, 2) as sub_total, y.name as currency, NULL, NULL, NULL |
413 | + FROM account_invoice_line i |
414 | + INNER JOIN account_invoice s ON s.id = i.invoice_id |
415 | + INNER JOIN res_currency y ON y.id = s.currency_id |
416 | + LEFT JOIN product_product p ON p.id = i.product_id |
417 | + WHERE s.id=%s AND i.account_id IS NULL |
418 | ORDER BY line_number, destination, cost_center, funding_pool |
419 | - """, (invoice_id, invoice_id, invoice_id)) |
420 | + """, (invoice_id, invoice_id, invoice_id, invoice_id)) |
421 | res = self._cr.fetchall() |
422 | self.total_amount = sum([line[7] or 0.0 for line in res]) |
423 | return res |
424 | @@ -88,11 +99,24 @@ |
425 | def get_total_amount(self): |
426 | return self.total_amount |
427 | |
428 | + def get_doc_type(self, inv): |
429 | + """ |
430 | + Returns the String corresponding to the invoice type. |
431 | + Note that using "getSel" doesn't work because "doc_type" is a fields.function. |
432 | + """ |
433 | + inv_doc_type = "" |
434 | + inv_obj = self.pool.get('account.invoice') |
435 | + for doc_type in inv_obj._get_invoice_type_list(self.cr, self.uid): |
436 | + if len(doc_type) >= 2 and inv.doc_type == doc_type[0]: |
437 | + inv_doc_type = doc_type[1] |
438 | + break |
439 | + return inv_doc_type |
440 | + |
441 | def get_journal_code(self, inv): |
442 | - ''' |
443 | + """ |
444 | If the SI has been (partially or totally) imported in a register, return the Journal Code |
445 | It the SI has been partially imported in several registers, return : "code1 / code2 / code3" |
446 | - ''' |
447 | + """ |
448 | journal_code_list = [] |
449 | if inv and inv.move_id: |
450 | absl_ids = self.pool.get('account.bank.statement.line').search(self.cr, self.uid, [('imported_invoice_line_ids', 'in', [x.id for x in inv.move_id.line_id])]) |
451 | |
452 | === modified file 'bin/addons/analytic_distribution/analytic_distribution.py' |
453 | --- bin/addons/analytic_distribution/analytic_distribution.py 2021-04-14 16:45:55 +0000 |
454 | +++ bin/addons/analytic_distribution/analytic_distribution.py 2022-01-06 16:20:57 +0000 |
455 | @@ -170,7 +170,7 @@ |
456 | account = self.pool.get('account.account').read(cr, uid, account_id, ['destination_ids']) |
457 | # Check Cost Center lines regarding destination/account and destination/CC links |
458 | for cc_line in distrib.cost_center_lines: |
459 | - if cc_line.destination_id.id not in account.get('destination_ids', []): |
460 | + if account and cc_line.destination_id.id not in account.get('destination_ids', []): |
461 | return 'invalid' |
462 | if not self.check_dest_cc_compatibility(cr, uid, cc_line.destination_id.id, |
463 | cc_line.analytic_id and cc_line.analytic_id.id or False, context=context): |
464 | @@ -193,7 +193,7 @@ |
465 | return 'invalid' |
466 | if doc_date and fp_line.analytic_id and not analytic_acc_obj.is_account_active(fp_line.analytic_id, doc_date): |
467 | return 'invalid' |
468 | - if fp_line.destination_id.id not in account.get('destination_ids', []): |
469 | + if account and fp_line.destination_id.id not in account.get('destination_ids', []): |
470 | return 'invalid' |
471 | if not self.check_dest_cc_compatibility(cr, uid, fp_line.destination_id.id, fp_line.cost_center_id.id, context=context): |
472 | return 'invalid' |
473 | |
474 | === modified file 'bin/addons/analytic_distribution/invoice.py' |
475 | --- bin/addons/analytic_distribution/invoice.py 2020-01-21 16:18:01 +0000 |
476 | +++ bin/addons/analytic_distribution/invoice.py 2022-01-06 16:20:57 +0000 |
477 | @@ -213,7 +213,7 @@ |
478 | res = {} |
479 | for invl in self.browse(cr, uid, ids): |
480 | res[invl.id] = '' |
481 | - if not invl.is_allocatable: |
482 | + if not invl.is_allocatable or (invl.allow_no_account and not invl.account_id): |
483 | continue |
484 | from_header = '' |
485 | if invl.have_analytic_distribution_from_header: |
486 | |
487 | === modified file 'bin/addons/msf_profile/i18n/fr_MF.po' |
488 | --- bin/addons/msf_profile/i18n/fr_MF.po 2022-01-05 16:30:54 +0000 |
489 | +++ bin/addons/msf_profile/i18n/fr_MF.po 2022-01-06 16:20:57 +0000 |
490 | @@ -106168,23 +106168,11 @@ |
491 | msgstr "Champ interne indiquant si le document est lié à un flux \"Supply\"" |
492 | |
493 | #. module: account_override |
494 | -#: code:addons/account_override/account_invoice_sync.py:120 |
495 | -#, python-format |
496 | -msgid "Account code %s not found." |
497 | -msgstr "Code comptable %s non trouvé." |
498 | - |
499 | -#. module: account_override |
500 | #: code:addons/account_override/account_invoice_sync.py:189 |
501 | #, python-format |
502 | msgid "Impossible to retrieve the currency." |
503 | msgstr "Impossible de récupérer la devise." |
504 | |
505 | -#. module: account_override |
506 | -#: code:addons/account_override/account_invoice_sync.py:117 |
507 | -#, python-format |
508 | -msgid "Impossible to retrieve the account code at line level." |
509 | -msgstr "Impossible de récupérer le code comptable au niveau d'une ligne." |
510 | - |
511 | #. modules: account_override, account |
512 | #: code:addons/account_override/account_invoice_sync.py:193 |
513 | #: code:addons/account/wizard/account_invoice_import.py:107 |
514 | @@ -106193,12 +106181,6 @@ |
515 | msgstr "Devise %s non trouvée ou inactive." |
516 | |
517 | #. module: account_override |
518 | -#: code:addons/account_override/account_invoice_sync.py:123 |
519 | -#, python-format |
520 | -msgid "Error when retrieving the account at line level." |
521 | -msgstr "Erreur lors de la récupération du compte au niveau d'une ligne." |
522 | - |
523 | -#. module: account_override |
524 | #: code:addons/account_override/account_invoice_sync.py:235 |
525 | #, python-format |
526 | msgid "The Intermission counterpart account is missing in the Company form or is inactive." |
527 | @@ -106217,12 +106199,6 @@ |
528 | msgstr "Impossible de récupérer la description de la ligne." |
529 | |
530 | #. module: account_override |
531 | -#: code:addons/account_override/account_invoice_sync.py:128 |
532 | -#, python-format |
533 | -msgid "The account \"%s - %s\" is inactive." |
534 | -msgstr "Le compte \"%s - %s\" est inactif." |
535 | - |
536 | -#. module: account_override |
537 | #: code:addons/account_override/account_invoice_sync.py:135 |
538 | #, python-format |
539 | msgid "Unit of Measure %s not found." |
540 | @@ -113224,6 +113200,28 @@ |
541 | msgid "You must select an old version of the Kit to be able to import from it" |
542 | msgstr "Vous devez sélectionner une ancienne version de ce Kit pour pouvoir importer depuis ce Kit" |
543 | |
544 | +#. module: account_override |
545 | +#: field:account.invoice.line,allow_no_account:0 |
546 | +msgid "Allow an empty account on the line" |
547 | +msgstr "Autoriser un compte vide sur la ligne" |
548 | + |
549 | +#. module: account_override |
550 | +#: sql_constraint:account.invoice.line:0 |
551 | +msgid "The invoice lines must have an account." |
552 | +msgstr "Les lignes de facture doivent avoir un compte." |
553 | + |
554 | +#. module: register_accounting |
555 | +#: code:addons/register_accounting/invoice.py:369 |
556 | +#, python-format |
557 | +msgid "The account is missing on the line No. %s." |
558 | +msgstr "Il manque le compte sur la ligne N°%s." |
559 | + |
560 | +#. module: account_override |
561 | +#: code:addons/account_override/invoice.py:1759 |
562 | +#, python-format |
563 | +msgid "Duplication not allowed. Please set an account on all lines first." |
564 | +msgstr "Duplication non autorisée. Veuillez d'abord définir un compte sur toutes les lignes." |
565 | + |
566 | #. module: analytic_override |
567 | #: field:account.analytic.line,ad_updated:0 |
568 | msgid "Analytic Distribution Updated" |
569 | |
570 | === modified file 'bin/addons/register_accounting/account_invoice_view.xml' |
571 | --- bin/addons/register_accounting/account_invoice_view.xml 2021-10-21 09:49:00 +0000 |
572 | +++ bin/addons/register_accounting/account_invoice_view.xml 2022-01-06 16:20:57 +0000 |
573 | @@ -49,7 +49,10 @@ |
574 | colors="red:analytic_distribution_state in ('invalid', 'invalid_small_amount') or inactive_product == True;black:inactive_product == False and analytic_distribution_state in ('none','valid')"> |
575 | <field name="name"/> |
576 | <field name="reference"/> |
577 | - <field domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('restricted_area', '=', 'invoice_lines')]" name="account_id"/> |
578 | + <field name="account_id" |
579 | + domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('restricted_area', '=', 'invoice_lines')]" |
580 | + required="1" |
581 | + /> |
582 | <button name="button_analytic_distribution" string="Analytical Distribution" type="object" icon="terp-stock_symbol-selection" |
583 | context="{'d_journal_id': parent.journal_id , 'd_partner_id': parent.partner_id, 'd_address_invoice_id':parent.address_invoice_id,'d_date_invoice': parent.date_invoice, 'd_register_posting_date': parent.register_posting_date, 'd_document_date': parent.document_date, 'd_account_id': parent.account_id, 'd_partner_bank_id': parent.partner_bank_id, 'd_payment_term': parent.payment_term, 'd_name': parent.name, 'd_origine': parent.origin, 'd_address_contact_id': parent.address_contact_id, 'd_user_id': parent.user_id, 'd_comment': parent.comment,'d_reference': parent.reference}" |
584 | /> |
585 | @@ -176,7 +179,10 @@ |
586 | <button name="button_open_analytic_lines" string="Have been corrected" type="object" icon="terp-mail-" attrs="{'invisible': [('is_corrected', '=', False)]}"/> |
587 | <field name="name"/> |
588 | <field name="reference" /> |
589 | - <field domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('restricted_area', '=', 'invoice_lines')]" name="account_id"/> |
590 | + <field name="account_id" |
591 | + domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('restricted_area', '=', 'invoice_lines')]" |
592 | + required="1" |
593 | + /> |
594 | <field name="analytic_distribution_state_recap" attrs="{'invisible': [('is_allocatable', '=', False)]}"/> |
595 | <field name="analytic_distribution_state" invisible="1"/> |
596 | <field name="have_analytic_distribution_from_header" invisible="1"/> |
597 | |
598 | === modified file 'bin/addons/register_accounting/invoice.py' |
599 | --- bin/addons/register_accounting/invoice.py 2017-08-18 14:07:26 +0000 |
600 | +++ bin/addons/register_accounting/invoice.py 2022-01-06 16:20:57 +0000 |
601 | @@ -358,6 +358,20 @@ |
602 | aal_obj.write(cr, uid, aal_ids, {'reference': reference}, context=context) |
603 | return True |
604 | |
605 | + def _check_empty_account(self, cr, uid, ids, context=None): |
606 | + """ |
607 | + Raises an error if one of the invoice lines has no account. |
608 | + """ |
609 | + if context is None: |
610 | + context = {} |
611 | + if isinstance(ids, (int, long)): |
612 | + ids = [ids] |
613 | + for inv in self.browse(cr, uid, ids, fields_to_fetch=['invoice_line'], context=context): |
614 | + for invl in inv.invoice_line: |
615 | + if not invl.account_id: |
616 | + raise osv.except_osv(_('Error'), _('The account is missing on the line No. %s.') % invl.line_number) |
617 | + return True |
618 | + |
619 | def action_open_invoice(self, cr, uid, ids, context=None, *args): |
620 | """ |
621 | Add down payment check after others verifications |
622 | @@ -368,6 +382,7 @@ |
623 | if isinstance(ids, (int, long)): |
624 | ids = [ids] |
625 | # Browse invoice and all invoice lines to detect a non-valid line |
626 | + self._check_empty_account(cr, uid, ids, context=context) |
627 | self._check_analytic_distribution_state(cr, uid, ids) |
628 | # Default behaviour |
629 | res = super(account_invoice, self).action_open_invoice(cr, uid, ids, context) |