Merge lp:~julie-w/unifield-server/US-5608 into lp:unifield-server

Proposed by jftempo
Status: Merged
Merged at revision: 5548
Proposed branch: lp:~julie-w/unifield-server/US-5608
Merge into: lp:unifield-server
Diff against target: 339 lines (+127/-18)
9 files modified
bin/addons/account/account.py (+28/-4)
bin/addons/account/account_invoice_view.xml (+3/-1)
bin/addons/account/account_view.xml (+1/-0)
bin/addons/account/invoice.py (+46/-8)
bin/addons/account/wizard/account_invoice_refund.py (+5/-4)
bin/addons/msf_partner/partner.py (+21/-0)
bin/addons/msf_profile/i18n/fr_MF.po (+20/-0)
bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv (+1/-1)
bin/addons/sync_client/update.py (+2/-0)
To merge this branch: bzr merge lp:~julie-w/unifield-server/US-5608
Reviewer Review Type Date Requested Status
UniField Reviewer Team Pending
Review via email: mp+373139@code.launchpad.net
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.py'
2--- bin/addons/account/account.py 2019-07-30 09:13:43 +0000
3+++ bin/addons/account/account.py 2019-09-24 13:32:21 +0000
4@@ -1909,6 +1909,9 @@
5 'parent_id':fields.many2one('account.tax', 'Parent Tax Account', select=True),
6 'child_ids':fields.one2many('account.tax', 'parent_id', 'Child Tax Accounts'),
7 'child_depend':fields.boolean('Tax on Children', help="Set if the tax computation is based on the computation of child taxes rather than on the total amount."),
8+ 'partner_id': fields.many2one('res.partner', 'Partner',
9+ domain=[('partner_type', '=', 'external'), ('active', '=', True)],
10+ ondelete='restrict'),
11 'python_compute':fields.text('Python Code'),
12 'python_compute_inv':fields.text('Python Code (reverse)'),
13 'python_applicable':fields.text('Python Code'),
14@@ -1963,11 +1966,31 @@
15 ids = self.search(cr, user, args, limit=limit, context=context or {})
16 return self.name_get(cr, user, ids, context=context)
17
18+ def _check_tax_partner(self, cr, uid, vals, context=None):
19+ """
20+ Raises an error in case the partner selected for the tax isn't allowed
21+ """
22+ if context is None:
23+ context = {}
24+ partner_obj = self.pool.get('res.partner')
25+ if vals.get('partner_id'):
26+ partner = partner_obj.browse(cr, uid, vals['partner_id'], fields_to_fetch=['active', 'partner_type', 'name'], context=context)
27+ if not partner.active or partner.partner_type != 'external':
28+ raise osv.except_osv(_('Error'),
29+ _("You can't link the tax to the Partner %s: only active external partners are allowed.") % partner.name)
30+
31+ def create(self, cr, uid, vals, context=None):
32+ if context is None:
33+ context = {}
34+ self._check_tax_partner(cr, uid, vals, context=context)
35+ return super(account_tax, self).create(cr, uid, vals, context=context)
36+
37 def write(self, cr, uid, ids, vals, context=None):
38 if not ids:
39 return True
40 if vals.get('type', False) and vals['type'] in ('none', 'code'):
41 vals.update({'amount': 0.0})
42+ self._check_tax_partner(cr, uid, vals, context=context)
43 return super(account_tax, self).write(cr, uid, ids, vals, context=context)
44
45 def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
46@@ -2041,9 +2064,9 @@
47 obj_partener_address = self.pool.get('res.partner.address')
48 for tax in taxes:
49 # we compute the amount for the current tax object and append it to the result
50-
51+ description = "%s%s%s" % (tax.name, partner and ' - ' or '', partner and partner.name or '') # tax name and INVOICE partner name
52 data = {'id':tax.id,
53- 'name':tax.description and tax.description + " - " + tax.name or tax.name,
54+ 'name': description,
55 'account_collected_id':tax.account_collected_id.id,
56 'account_paid_id':tax.account_paid_id.id,
57 'base_code_id': tax.base_code_id.id,
58@@ -2200,10 +2223,11 @@
59 todo = 0
60 else:
61 todo = 1
62+ description = "%s%s%s" % (tax.name, partner and ' - ' or '', partner and partner.name or '') # tax name and INVOICE partner name
63 res.append({
64 'id': tax.id,
65 'todo': todo,
66- 'name': tax.name,
67+ 'name': description,
68 'amount': amount,
69 'account_collected_id': tax.account_collected_id.id,
70 'account_paid_id': tax.account_paid_id.id,
71@@ -2245,7 +2269,7 @@
72 tax = {'name':'', 'amount':0.0, 'account_collected_id':1, 'account_paid_id':2}
73 one tax for each tax id in IDS and their children
74 """
75- res = self._unit_compute_inv(cr, uid, taxes, price_unit, address_id, product, partner=None)
76+ res = self._unit_compute_inv(cr, uid, taxes, price_unit, address_id, product, partner=partner)
77 total = 0.0
78 obj_precision = self.pool.get('decimal.precision')
79 for r in res:
80
81=== modified file 'bin/addons/account/account_invoice_view.xml'
82--- bin/addons/account/account_invoice_view.xml 2019-07-29 15:00:38 +0000
83+++ bin/addons/account/account_invoice_view.xml 2019-09-24 13:32:21 +0000
84@@ -216,13 +216,15 @@
85 <field name="tax_line" nolabel="1" attrs="{'invisible': [('vat_ok', '=', False)], 'readonly': ['|', ('state','!=', 'draft'), '&amp;', ('type', '=', 'in_invoice'), ('synced', '=', True)]}">
86 <tree editable="bottom" string="Taxes">
87 <field name="invoice_id" invisible="True"/>
88- <field name="account_tax_id" on_change="tax_code_change(account_tax_id,parent.amount_untaxed,context)"/>
89+ <field name="account_tax_id" on_change="tax_code_change(account_tax_id, parent.amount_untaxed, parent.partner_id, context)"/>
90 <field name="name"/>
91
92 <field name="account_id" groups="account.group_account_invoice"
93 domain="[('type', 'not in', ['view', 'consolidation']),
94 ('user_type_code', '=', 'tax')]"/>
95
96+ <field name="partner_id" readonly="1"/>
97+
98 <field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/>
99 <field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/>
100
101
102=== modified file 'bin/addons/account/account_view.xml'
103--- bin/addons/account/account_view.xml 2019-01-31 14:39:54 +0000
104+++ bin/addons/account/account_view.xml 2019-09-24 13:32:21 +0000
105@@ -972,6 +972,7 @@
106 <field name="type_tax_use"/>
107 <field name="price_include"/>
108 <field name="active"/>
109+ <field name="partner_id"/>
110 <field name="company_id" widget="selection" groups="base.group_multi_company"/>
111 </group>
112 <notebook colspan="4">
113
114=== modified file 'bin/addons/account/invoice.py'
115--- bin/addons/account/invoice.py 2019-07-25 14:58:06 +0000
116+++ bin/addons/account/invoice.py 2019-09-24 13:32:21 +0000
117@@ -1111,7 +1111,7 @@
118 def line_get_convert(self, cr, uid, x, part, date, context=None):
119 return {
120 'date_maturity': x.get('date_maturity', False),
121- 'partner_id': part,
122+ 'partner_id': x.get('partner_id') or part,
123 'name': x['name'][:64],
124 'date': date,
125 'debit_currency': x['price']>0 and x['price'],
126@@ -1856,13 +1856,35 @@
127 raise osv.except_osv(_('Warning !'), _('The Untaxed Amount is zero. Please press the Save & Edit button before saving the %s tax.') % (vals['name']))
128 return True
129
130+ def _update_tax_partner(self, cr, uid, vals, context=None):
131+ """
132+ Updates vals with the partner of the related tax
133+
134+ Note that in case a partner_id is already in vals, it is used (e.g. in case of a SI refund the SR tax lines must be exactly
135+ the same as the SI ones, even if the partner linked to the related account.tax has changed in the meantime)
136+ """
137+ if context is None:
138+ context = {}
139+ tax_obj = self.pool.get('account.tax')
140+ if 'partner_id' not in vals and 'account_tax_id' in vals:
141+ tax_partner_id = False
142+ if vals['account_tax_id']: # note that at doc level it's possible not to have any link to a tax from the system
143+ tax = tax_obj.browse(cr, uid, vals['account_tax_id'], fields_to_fetch=['partner_id'], context=context)
144+ tax_partner_id = tax.partner_id and tax.partner_id.id or False
145+ vals.update({'partner_id': tax_partner_id})
146
147 def create(self, cr, uid, vals, context=None):
148- if context == None:
149+ if context is None:
150 context = {}
151 self._check_untaxed_amount(cr, uid, vals, context)
152+ self._update_tax_partner(cr, uid, vals, context=context)
153 return super(account_invoice_tax, self).create(cr, uid, vals, context=context)
154
155+ def write(self, cr, uid, ids, vals, context=None):
156+ if context is None:
157+ context = {}
158+ self._update_tax_partner(cr, uid, vals, context=context)
159+ return super(account_invoice_tax, self).write(cr, uid, ids, vals, context=context)
160
161 def _count_factor(self, cr, uid, ids, name, args, context=None):
162 res = {}
163@@ -1896,16 +1918,31 @@
164 'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
165 'factor_base': fields.function(_count_factor, method=True, string='Multipication factor for Base code', type='float', multi="all"),
166 'factor_tax': fields.function(_count_factor, method=True, string='Multipication factor Tax code', type='float', multi="all"),
167- 'account_tax_id': fields.many2one('account.tax', 'Tax', domain=[('price_include', '=', False)])
168+ 'account_tax_id': fields.many2one('account.tax', 'Tax', domain=[('price_include', '=', False)]),
169+ 'partner_id': fields.many2one('res.partner', 'Partner', ondelete='restrict'),
170 }
171
172-
173- def tax_code_change(self, cr, uid, ids, account_tax_id, amount_untaxed, context=None):
174+ def tax_code_change(self, cr, uid, ids, account_tax_id, amount_untaxed, inv_partner_id, context=None):
175+ if context is None:
176+ context = {}
177 ret = {}
178 if account_tax_id:
179 atx_obj = self.pool.get('account.tax')
180- atx = atx_obj.browse(cr, uid, account_tax_id, context=context)
181- ret = {'value': {'account_id': atx.account_collected_id.id, 'name': "{0} - {1}".format(atx.name, atx.description or ''), 'base_amount': amount_untaxed, 'amount': self._calculate_tax(cr, uid, account_tax_id, amount_untaxed)}}
182+ partner_obj = self.pool.get('res.partner')
183+ inv_partner = inv_partner_id and partner_obj.browse(cr, uid, inv_partner_id,
184+ fields_to_fetch=['name', 'lang'], context=context) or None
185+ inv_partner_name = inv_partner and inv_partner.name or ''
186+ # use the language of the partner for the tax name (to be consistent with what's done when clicking on Compute Taxes)
187+ inv_partner_lang = inv_partner and inv_partner.lang or ''
188+ new_context = context.copy()
189+ if inv_partner_lang:
190+ new_context.update({'lang': inv_partner_lang})
191+ tax = atx_obj.browse(cr, uid, account_tax_id, fields_to_fetch=['name', 'account_collected_id'], context=new_context)
192+ description = "%s%s%s" % (tax.name, inv_partner_name and ' - ' or '', inv_partner_name or '')
193+ ret = {'value': {'account_id': tax.account_collected_id and tax.account_collected_id.id or False,
194+ 'name': description,
195+ 'base_amount': amount_untaxed,
196+ 'amount': self._calculate_tax(cr, uid, account_tax_id, amount_untaxed)}}
197 return ret
198
199 def _calculate_tax(self, cr, uid, account_tax_id, amount_untaxed):
200@@ -2023,7 +2060,8 @@
201 'price': t['amount'] or 0.0,
202 'account_id': t['account_id'],
203 'tax_code_id': t['tax_code_id'],
204- 'tax_amount': t['tax_amount']
205+ 'tax_amount': t['tax_amount'],
206+ 'partner_id': t['partner_id'],
207 })
208 return res
209
210
211=== modified file 'bin/addons/account/wizard/account_invoice_refund.py'
212--- bin/addons/account/wizard/account_invoice_refund.py 2019-07-25 15:47:28 +0000
213+++ bin/addons/account/wizard/account_invoice_refund.py 2019-09-24 13:32:21 +0000
214@@ -116,11 +116,12 @@
215 def _get_reconcilable_amls(self, aml_list, to_reconcile_dict):
216 """
217 Fill in to_reconcile_dict with the aml from aml_list having a reconcilable account
218- (key = account id, value = list of aml ids)
219+ key = tuple with (account id, partner_id, is_counterpart)
220+ value = list of aml ids
221 """
222 for ml in aml_list:
223 if ml.account_id.reconcile:
224- key = (ml.account_id.id, ml.is_counterpart)
225+ key = (ml.account_id.id, ml.partner_id and ml.partner_id.id or False, ml.is_counterpart)
226 to_reconcile_dict.setdefault(key, []).append(ml.id)
227
228 def compute_refund(self, cr, uid, ids, mode='refund', context=None):
229@@ -234,8 +235,8 @@
230 self._get_reconcilable_amls(movelines, to_reconcile)
231 self._get_reconcilable_amls(refund.move_id.line_id, to_reconcile)
232 # reconcile the lines grouped by account
233- for account_id, is_counterpart in to_reconcile:
234- account_m_line_obj.reconcile(cr, uid, to_reconcile[(account_id, is_counterpart)],
235+ for account_id, partner_id, is_counterpart in to_reconcile:
236+ account_m_line_obj.reconcile(cr, uid, to_reconcile[(account_id, partner_id, is_counterpart)],
237 writeoff_period_id=period,
238 writeoff_journal_id = inv.journal_id.id,
239 writeoff_acc_id=account_id
240
241=== modified file 'bin/addons/msf_partner/partner.py'
242--- bin/addons/msf_partner/partner.py 2019-02-08 16:27:30 +0000
243+++ bin/addons/msf_partner/partner.py 2019-09-24 13:32:21 +0000
244@@ -666,6 +666,26 @@
245
246 return True
247
248+ def _check_existing_tax_partner(self, cr, uid, ids, context=None):
249+ """
250+ Raises an error in case the partner has been used in a tax (to be used when trying to de-activate partners)
251+ """
252+ if context is None:
253+ context = {}
254+ tax_obj = self.pool.get('account.tax')
255+ inv_obj = self.pool.get('account.invoice')
256+ inv_tax_obj = self.pool.get('account.invoice.tax')
257+ if tax_obj.search_exist(cr, uid, [('partner_id', 'in', ids)], context=context):
258+ raise osv.except_osv(_('Warning'),
259+ _("Impossible to deactivate a partner used for a tax."))
260+ # use case: partner linked to a tax, related tax lines generated and partner removed from the tax
261+ # Note that only draft account.invoices need to be checked as other ones have generated JIs (so are already checked)
262+ draft_invoice_ids = inv_obj.search(cr, uid, [('state', '=', 'draft')], order='NO_ORDER', context=context)
263+ if draft_invoice_ids:
264+ if inv_tax_obj.search_exist(cr, uid, [('partner_id', 'in', ids), ('invoice_id', 'in', draft_invoice_ids)], context=context):
265+ raise osv.except_osv(_('Warning'),
266+ _("Impossible to deactivate a partner used in the tax line of an invoice."))
267+
268 def write(self, cr, uid, ids, vals, context=None):
269 if not ids:
270 return True
271@@ -701,6 +721,7 @@
272 raise osv.except_osv(_('Warning'),
273 _("""The following documents linked to the partner need to be closed before deactivating the partner: %s"""
274 ) % (objects_linked_to_partner))
275+ self._check_existing_tax_partner(cr, uid, ids, context=context)
276
277 if vals.get('name'):
278 vals['name'] = vals['name'].replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ').strip()
279
280=== modified file 'bin/addons/msf_profile/i18n/fr_MF.po'
281--- bin/addons/msf_profile/i18n/fr_MF.po 2019-09-17 16:00:23 +0000
282+++ bin/addons/msf_profile/i18n/fr_MF.po 2019-09-24 13:32:21 +0000
283@@ -49841,6 +49841,8 @@
284 #: report:addons/stock/report/stock_delivery_report_xls.mako:186
285 #: report:addons/stock/report/stock_delivery_report_xls.mako:211
286 #: field:stock.delivery.wizard,partner_id:0
287+#: field:account.invoice.tax,partner_id:0
288+#: field:account.tax,partner_id:0
289 #, python-format
290 msgid "Partner"
291 msgstr "Partenaire"
292@@ -107372,3 +107374,21 @@
293 #: report:purchase.order.merged:0
294 msgid "Functional total cost :"
295 msgstr "Total Coût Fonctionnel :"
296+
297+#. module: msf_partner
298+#: code:addons/msf_partner/partner.py:680
299+#, python-format
300+msgid "Impossible to deactivate a partner used for a tax."
301+msgstr "Impossible de désactiver un partenaire utilisé pour une taxe."
302+
303+#. module: msf_partner
304+#: code:addons/msf_partner/partner.py:687
305+#, python-format
306+msgid "Impossible to deactivate a partner used in the tax line of an invoice."
307+msgstr "Impossible de désactiver un partenaire utilisé dans la ligne de taxe d'une facture."
308+
309+#. module: account
310+#: code:addons/account/account.py:1980
311+#, python-format
312+msgid "You can't link the tax to the Partner %s: only active external partners are allowed."
313+msgstr "Vous ne pouvez pas lier la taxe au partenaire %s : seuls les partenaires externes actifs sont autorisés."
314
315=== modified file 'bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv'
316--- bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv 2019-08-08 13:55:43 +0000
317+++ bin/addons/msf_sync_data_server/data/sync_server.sync_rule.csv 2019-09-24 13:32:21 +0000
318@@ -126,7 +126,7 @@
319 msf_sync_data_server.standard_product_list_line,TRUE,TRUE,TRUE,TRUE,bidirectional,Down,"[('list_id' , 'in', ('product.list', 'id', [('standard_list_ok','=','True')]))]","['comment','list_id/id','ref','name/id']",OC,product.list.line,,Standard Product List Line,Valid,,606
320 msf_sync_data_server.tax_code,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,[],"['code', 'info', 'name', 'notprintable', 'sign']",OC,account.tax.code,,Tax Code,Valid,,610
321 msf_sync_data_server.tax_code_tree,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,"[('parent_id','!=','')]",['parent_id/id'],OC,account.tax.code,,Tax Code Tree,Valid,,611
322-msf_sync_data_server.account_tax,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,[],"['account_collected_id/id', 'account_paid_id/id', 'active', 'amount', 'applicable_type', 'base_code_id/id', 'base_sign', 'child_depend', 'description', 'domain', 'include_base_amount', 'name', 'price_include', 'python_applicable', 'python_compute', 'python_compute_inv', 'ref_base_code_id/id', 'ref_base_sign', 'ref_tax_code_id/id', 'ref_tax_sign', 'sequence', 'tax_code_id/id', 'tax_sign', 'type', 'type_tax_use']",OC,account.tax,,Account Tax,Valid,,612
323+msf_sync_data_server.account_tax,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,[],"['account_collected_id/id', 'account_paid_id/id', 'active', 'amount', 'applicable_type', 'base_code_id/id', 'base_sign', 'child_depend', 'description', 'domain', 'include_base_amount', 'name', 'price_include', 'python_applicable', 'python_compute', 'python_compute_inv', 'ref_base_code_id/id', 'ref_base_sign', 'ref_tax_code_id/id', 'ref_tax_sign', 'sequence', 'tax_code_id/id', 'tax_sign', 'type', 'type_tax_use', 'partner_id/id']",OC,account.tax,,Account Tax,Valid,,612
324 msf_sync_data_server.account_tax_tree,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,"[('parent_id','!=','')]",['parent_id/id'],OC,account.tax,,Account Tax Tree,Valid,,613
325 msf_sync_data_server.composition_kit,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,"[('state','=','completed'),('composition_type','=','theoretical')]","['active', 'composition_creation_date', 'composition_description', 'composition_product_id/id', 'composition_type', 'composition_version', 'composition_version_txt', 'name', 'state']",OC,composition.kit,,Theoretical Kit Composition List,Valid,,620
326 msf_sync_data_server.composition_item,TRUE,TRUE,FALSE,TRUE,bidirectional,Down,"[('item_kit_id' , 'in' , ('composition.kit' , 'id' , [('state','=','completed'),('composition_type','=','theoretical')]))]","['item_asset_id/id', 'item_kit_id/id', 'item_module', 'item_product_id/id', 'item_qty', 'item_uom_id/id']",OC,composition.item,,Theoretical Kit Composition List Line,Valid,,621
327
328=== modified file 'bin/addons/sync_client/update.py'
329--- bin/addons/sync_client/update.py 2019-04-03 09:52:48 +0000
330+++ bin/addons/sync_client/update.py 2019-09-24 13:32:21 +0000
331@@ -964,6 +964,8 @@
332
333 if update.model == 'res.partner.address' and field == 'partner_id/id':
334 return {'res': False, 'error_message': 'partner_id %s not found' % xmlid}
335+ if update.model == 'account.tax' and field == 'partner_id/id':
336+ return {'res': False, 'error_message': 'partner_id %s not found' % xmlid}
337 if update.model == 'account.analytic.line' and field in ('cost_center_id/id', 'destination_id/id'):
338 return {'res': False, 'error_message': 'Analytic Account %s not found' % xmlid}
339 fb = fallback.get(field, False)

Subscribers

People subscribed via source and target branches